From a2fdbec6742a86e62144b3d67a14a72c57c4d985 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20Tigeot?= Date: Fri, 2 Jan 2015 13:51:10 +0100 Subject: [PATCH] drm/i915: Update to Linux 3.9.11 * Various bug fixes and small improvements * Better handling of GPU hangs, improved driver robustness * Support for the display power well on Haswell GPUs * Support for more Haswell GPU (PCI ID) models --- sys/dev/drm/drm_crtc.c | 278 ++--- sys/dev/drm/drm_drv.c | 10 +- sys/dev/drm/drm_edid.c | 56 +- sys/dev/drm/i915/Makefile | 2 + sys/dev/drm/i915/i915_debugfs.c | 244 +++- sys/dev/drm/i915/i915_dma.c | 249 +++- sys/dev/drm/i915/i915_drv.c | 356 +++--- sys/dev/drm/i915/i915_drv.h | 530 +++++--- sys/dev/drm/i915/i915_gem.c | 853 ++++++++----- sys/dev/drm/i915/i915_gem_context.c | 22 +- sys/dev/drm/i915/i915_gem_evict.c | 9 +- sys/dev/drm/i915/i915_gem_execbuffer.c | 358 +++--- sys/dev/drm/i915/i915_gem_gtt.c | 366 ++++-- sys/dev/drm/i915/i915_gem_stolen.c | 197 +++ sys/dev/drm/i915/i915_gem_tiling.c | 41 +- sys/dev/drm/i915/i915_irq.c | 419 ++++--- sys/dev/drm/i915/i915_reg.h | 431 ++++--- sys/dev/drm/i915/i915_suspend.c | 548 +-------- sys/dev/drm/i915/i915_trace.h | 45 + .../drm/i915/{i915_suspend.c => i915_ums.c} | 473 +------- sys/dev/drm/i915/intel_crt.c | 31 +- sys/dev/drm/i915/intel_ddi.c | 52 +- sys/dev/drm/i915/intel_display.c | 1080 ++++++++--------- sys/dev/drm/i915/intel_dp.c | 403 +++--- sys/dev/drm/i915/intel_drv.h | 70 +- sys/dev/drm/i915/intel_fb.c | 128 +- sys/dev/drm/i915/intel_hdmi.c | 109 +- sys/dev/drm/i915/intel_i2c.c | 653 ++++++---- sys/dev/drm/i915/intel_lvds.c | 259 +++- sys/dev/drm/i915/intel_modes.c | 8 +- sys/dev/drm/i915/intel_opregion.c | 10 +- sys/dev/drm/i915/intel_overlay.c | 36 +- sys/dev/drm/i915/intel_panel.c | 8 +- sys/dev/drm/i915/intel_pm.c | 188 ++- sys/dev/drm/i915/intel_ringbuffer.c | 131 +- sys/dev/drm/i915/intel_ringbuffer.h | 11 +- sys/dev/drm/i915/intel_sdvo.c | 143 ++- sys/dev/drm/i915/intel_sprite.c | 50 +- sys/dev/drm/i915/intel_tv.c | 11 +- sys/dev/drm/include/drm/drmP.h | 23 +- sys/dev/drm/include/drm/drm_crtc.h | 67 +- sys/dev/drm/include/drm/drm_edid.h | 15 + sys/dev/drm/include/drm/drm_global.h | 1 - sys/dev/drm/include/uapi_drm/drm.h | 4 +- sys/dev/drm/include/uapi_drm/drm_mode.h | 8 +- sys/dev/drm/include/uapi_drm/i915_drm.h | 20 + 46 files changed, 5020 insertions(+), 3986 deletions(-) create mode 100644 sys/dev/drm/i915/i915_gem_stolen.c create mode 100644 sys/dev/drm/i915/i915_trace.h copy sys/dev/drm/i915/{i915_suspend.c => i915_ums.c} (52%) diff --git a/sys/dev/drm/drm_crtc.c b/sys/dev/drm/drm_crtc.c index 0554e6a299..3353cf1d28 100644 --- a/sys/dev/drm/drm_crtc.c +++ b/sys/dev/drm/drm_crtc.c @@ -39,6 +39,40 @@ #include #include +/** + * drm_modeset_lock_all - take all modeset locks + * @dev: drm device + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. + */ +void drm_modeset_lock_all(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) +// mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex); + lockmgr(&crtc->mutex, LK_EXCLUSIVE); +} +EXPORT_SYMBOL(drm_modeset_lock_all); + +/** + * drm_modeset_unlock_all - drop all modeset locks + * @dev: device + */ +void drm_modeset_unlock_all(struct drm_device *dev) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + lockmgr(&crtc->mutex, LK_RELEASE); + + lockmgr(&dev->mode_config.mutex, LK_RELEASE); +} +EXPORT_SYMBOL(drm_modeset_unlock_all); + /* Avoid boilerplate. I'm tired of typing. */ #define DRM_ENUM_NAME_FN(fnname, list) \ char *fnname(int val) \ @@ -339,6 +373,50 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_reference); +static void drm_framebuffer_free_bug(struct kref *kref) +{ + BUG(); +} + +static void __drm_framebuffer_unreference(struct drm_framebuffer *fb) +{ + DRM_DEBUG("FB ID: %d\n", fb->base.id); + kref_put(&fb->refcount, drm_framebuffer_free_bug); +} + +/* dev->mode_config.fb_lock must be held! */ +static void __drm_framebuffer_unregister(struct drm_device *dev, + struct drm_framebuffer *fb) +{ + mutex_lock(&dev->mode_config.idr_mutex); + idr_remove(&dev->mode_config.crtc_idr, fb->base.id); + mutex_unlock(&dev->mode_config.idr_mutex); + + fb->base.id = 0; + + __drm_framebuffer_unreference(fb); +} + +/** + * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr + * @fb: fb to unregister + * + * Drivers need to call this when cleaning up driver-private framebuffers, e.g. + * those used for fbdev. Note that the caller must hold a reference of it's own, + * i.e. the object may not be destroyed through this call (since it'll lead to a + * locking inversion). + */ +void drm_framebuffer_unregister_private(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + + mutex_lock(&dev->mode_config.fb_lock); + /* Mark fb as reaped and drop idr ref. */ + __drm_framebuffer_unregister(dev, fb); + mutex_unlock(&dev->mode_config.fb_lock); +} +EXPORT_SYMBOL(drm_framebuffer_unregister_private); + /** * drm_framebuffer_cleanup - remove a framebuffer object * @fb: framebuffer to remove @@ -518,10 +596,7 @@ EXPORT_SYMBOL(drm_mode_remove); * @dev: DRM device * @connector: the connector to init * @funcs: callbacks for this connector - * @name: user visible name of the connector - * - * LOCKING: - * Takes mode config lock. + * @connector_type: user visible type of the connector * * Initialises a preallocated connector. Connectors should be * subclassed as part of driver connector objects. @@ -548,7 +623,6 @@ int drm_connector_init(struct drm_device *dev, connector->connector_type = connector_type; connector->connector_type_id = ++drm_connector_enum_list[connector_type].count; /* TODO */ - INIT_LIST_HEAD(&connector->user_modes); INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); connector->edid_blob_ptr = NULL; @@ -576,9 +650,6 @@ EXPORT_SYMBOL(drm_connector_init); * drm_connector_cleanup - cleans up an initialised connector * @connector: connector to cleanup * - * LOCKING: - * Takes mode config lock. - * * Cleans up the connector but doesn't free the object. */ void drm_connector_cleanup(struct drm_connector *connector) @@ -592,9 +663,6 @@ void drm_connector_cleanup(struct drm_connector *connector) list_for_each_entry_safe(mode, t, &connector->modes, head) drm_mode_remove(connector, mode); - list_for_each_entry_safe(mode, t, &connector->user_modes, head) - drm_mode_remove(connector, mode); - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); drm_mode_object_put(dev, &connector->base); list_del(&connector->head); @@ -2595,194 +2663,6 @@ void drm_fb_release(struct drm_file *priv) lockmgr(&dev->mode_config.mutex, LK_RELEASE); } -/** - * drm_mode_attachmode - add a mode to the user mode list - * @dev: DRM device - * @connector: connector to add the mode to - * @mode: mode to add - * - * Add @mode to @connector's user mode list. - */ -static void drm_mode_attachmode(struct drm_device *dev, - struct drm_connector *connector, - struct drm_display_mode *mode) -{ - list_add_tail(&mode->head, &connector->user_modes); -} - -int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc, - const struct drm_display_mode *mode) -{ - struct drm_connector *connector; - int ret = 0; - struct drm_display_mode *dup_mode, *next; - LINUX_LIST_HEAD(list); - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder) - continue; - if (connector->encoder->crtc == crtc) { - dup_mode = drm_mode_duplicate(dev, mode); - if (!dup_mode) { - ret = -ENOMEM; - goto out; - } - list_add_tail(&dup_mode->head, &list); - } - } - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder) - continue; - if (connector->encoder->crtc == crtc) - list_move_tail(list.next, &connector->user_modes); - } - - WARN_ON(!list_empty(&list)); - - out: - list_for_each_entry_safe(dup_mode, next, &list, head) - drm_mode_destroy(dev, dup_mode); - - return ret; -} -EXPORT_SYMBOL(drm_mode_attachmode_crtc); - -static int drm_mode_detachmode(struct drm_device *dev, - struct drm_connector *connector, - struct drm_display_mode *mode) -{ - int found = 0; - int ret = 0; - struct drm_display_mode *match_mode, *t; - - list_for_each_entry_safe(match_mode, t, &connector->user_modes, head) { - if (drm_mode_equal(match_mode, mode)) { - list_del(&match_mode->head); - drm_mode_destroy(dev, match_mode); - found = 1; - break; - } - } - - if (!found) - ret = -EINVAL; - - return ret; -} - -int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode) -{ - struct drm_connector *connector; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_mode_detachmode(dev, connector, mode); - } - return 0; -} -EXPORT_SYMBOL(drm_mode_detachmode_crtc); - -/** - * drm_fb_attachmode - Attach a user mode to an connector - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * This attaches a user specified mode to an connector. - * Called by the user via ioctl. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_mode_attachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_mode_cmd *mode_cmd = data; - struct drm_connector *connector; - struct drm_display_mode *mode; - struct drm_mode_object *obj; - struct drm_mode_modeinfo *umode = &mode_cmd->mode; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); - - obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -EINVAL; - goto out; - } - connector = obj_to_connector(obj); - - mode = drm_mode_create(dev); - if (!mode) { - ret = -ENOMEM; - goto out; - } - - ret = drm_crtc_convert_umode(mode, umode); - if (ret) { - DRM_DEBUG_KMS("Invalid mode\n"); - drm_mode_destroy(dev, mode); - goto out; - } - - drm_mode_attachmode(dev, connector, mode); -out: - lockmgr(&dev->mode_config.mutex, LK_RELEASE); - return ret; -} - - -/** - * drm_fb_detachmode - Detach a user specified mode from an connector - * @inode: inode from the ioctl - * @filp: file * from the ioctl - * @cmd: cmd from ioctl - * @arg: arg from ioctl - * - * Called by the user via ioctl. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_mode_detachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv) -{ - struct drm_mode_object *obj; - struct drm_mode_mode_cmd *mode_cmd = data; - struct drm_connector *connector; - struct drm_display_mode mode; - struct drm_mode_modeinfo *umode = &mode_cmd->mode; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; - - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); - - obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -EINVAL; - goto out; - } - connector = obj_to_connector(obj); - - ret = drm_crtc_convert_umode(&mode, umode); - if (ret) { - DRM_DEBUG_KMS("Invalid mode\n"); - goto out; - } - - ret = drm_mode_detachmode(dev, connector, &mode); -out: - lockmgr(&dev->mode_config.mutex, LK_RELEASE); - return ret; -} - struct drm_property *drm_property_create(struct drm_device *dev, int flags, const char *name, int num_values) { diff --git a/sys/dev/drm/drm_drv.c b/sys/dev/drm/drm_drv.c index e5861f8cfe..ba122d7bed 100644 --- a/sys/dev/drm/drm_drv.c +++ b/sys/dev/drm/drm_drv.c @@ -164,8 +164,8 @@ static drm_ioctl_desc_t drm_ioctls[256] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_connector_property_set_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED), @@ -308,7 +308,7 @@ int drm_attach(device_t kdev, drm_pci_id_list_t *idlist) lwkt_serialize_init(&dev->irq_lock); lockinit(&dev->vbl_lock, "drmvbl", 0, LK_CANRECURSE); lockinit(&dev->event_lock, "drmev", 0, LK_CANRECURSE); - lockinit(&dev->dev_struct_lock, "drmslk", 0, LK_CANRECURSE); + lockinit(&dev->struct_mutex, "drmslk", 0, LK_CANRECURSE); error = drm_load(dev); if (error) @@ -553,7 +553,7 @@ error: lockuninit(&dev->vbl_lock); lockuninit(&dev->dev_lock); lockuninit(&dev->event_lock); - lockuninit(&dev->dev_struct_lock); + lockuninit(&dev->struct_mutex); return retcode; } @@ -619,7 +619,7 @@ static void drm_unload(struct drm_device *dev) lockuninit(&dev->vbl_lock); lockuninit(&dev->dev_lock); lockuninit(&dev->event_lock); - lockuninit(&dev->dev_struct_lock); + lockuninit(&dev->struct_mutex); } int drm_version(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/sys/dev/drm/drm_edid.c b/sys/dev/drm/drm_edid.c index b3bec1b9ea..a71be1c286 100644 --- a/sys/dev/drm/drm_edid.c +++ b/sys/dev/drm/drm_edid.c @@ -26,8 +26,6 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * - * $FreeBSD: head/sys/dev/drm2/drm_edid.c 249041 2013-04-03 08:27:35Z dumbbell $ */ #include @@ -1497,9 +1495,11 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define VIDEO_BLOCK 0x02 #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 +#define VIDEO_CAPABILITY_BLOCK 0x07 #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) +#define EDID_CEA_VCDB_QS (1 << 6) /** * Search EDID for CEA extension block. @@ -1531,7 +1531,7 @@ EXPORT_SYMBOL(drm_find_cea_extension); * Looks for a CEA mode matching given drm_display_mode. * Returns its CEA Video ID code, or 0 if not found. */ -u8 drm_match_cea_mode(struct drm_display_mode *to_match) +u8 drm_match_cea_mode(const struct drm_display_mode *to_match) { u8 mode; @@ -1914,6 +1914,37 @@ end: } EXPORT_SYMBOL(drm_detect_monitor_audio); +/** + * drm_rgb_quant_range_selectable - is RGB quantization range selectable? + * + * Check whether the monitor reports the RGB quantization range selection + * as supported. The AVI infoframe can then be used to inform the monitor + * which quantization range (full or limited) is used. + */ +bool drm_rgb_quant_range_selectable(struct edid *edid) +{ + u8 *edid_ext; + int i, start, end; + + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return false; + + if (cea_db_offsets(edid_ext, &start, &end)) + return false; + + for_each_cea_db(edid_ext, i, start, end) { + if (cea_db_tag(&edid_ext[i]) == VIDEO_CAPABILITY_BLOCK && + cea_db_payload_len(&edid_ext[i]) == 2) { + DRM_DEBUG_KMS("CEA VCDB 0x%02x\n", edid_ext[i + 2]); + return edid_ext[i + 2] & EDID_CEA_VCDB_QS; + } + } + + return false; +} +EXPORT_SYMBOL(drm_rgb_quant_range_selectable); + /** * drm_add_display_info - pull display info out if present * @edid: EDID data @@ -2092,22 +2123,3 @@ int drm_add_modes_noedid(struct drm_connector *connector, return num_modes; } EXPORT_SYMBOL(drm_add_modes_noedid); - -/** - * drm_mode_cea_vic - return the CEA-861 VIC of a given mode - * @mode: mode - * - * RETURNS: - * The VIC number, 0 in case it's not a CEA-861 mode. - */ -uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode) -{ - uint8_t i; - - for (i = 0; i < drm_num_cea_modes; i++) - if (drm_mode_equal(mode, &edid_cea_modes[i])) - return i + 1; - - return 0; -} -EXPORT_SYMBOL(drm_mode_cea_vic); diff --git a/sys/dev/drm/i915/Makefile b/sys/dev/drm/i915/Makefile index a6e972c909..b4821d55dc 100644 --- a/sys/dev/drm/i915/Makefile +++ b/sys/dev/drm/i915/Makefile @@ -8,9 +8,11 @@ SRCS = \ i915_gem_execbuffer.c \ i915_gem_evict.c \ i915_gem_gtt.c \ + i915_gem_stolen.c \ i915_gem_tiling.c \ i915_irq.c \ i915_suspend.c \ + i915_ums.c \ intel_bios.c \ intel_crt.c \ intel_ddi.c \ diff --git a/sys/dev/drm/i915/i915_debugfs.c b/sys/dev/drm/i915/i915_debugfs.c index c415636c5a..4e5d70a10c 100644 --- a/sys/dev/drm/i915/i915_debugfs.c +++ b/sys/dev/drm/i915/i915_debugfs.c @@ -99,7 +99,7 @@ static const char *cache_level_str(int type) static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { - seq_printf(m, "%pK: %s%s %8zdKiB %04x %04x %d %d %d%s%s%s", + seq_printf(m, "%pK: %s%s %8zdKiB %02x %02x %d %d %d%s%s%s", &obj->base, get_pin_flag(obj), get_tiling_flag(obj), @@ -121,6 +121,8 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) if (obj->gtt_space != NULL) seq_printf(m, " (gtt offset: %08x, size: %08x)", obj->gtt_offset, (unsigned int)obj->gtt_space->size); + if (obj->stolen) + seq_printf(m, " (stolen: %08lx)", obj->stolen->start); if (obj->pin_mappable || obj->fault_mappable) { char s[3], *t = s; if (obj->pin_mappable) @@ -253,8 +255,9 @@ static int i915_gem_object_info(struct seq_file *m, void* data) seq_printf(m, "%u fault mappable objects, %zu bytes\n", count, size); - seq_printf(m, "%zu [%zu] gtt total\n", - dev_priv->mm.gtt_total, dev_priv->mm.mappable_gtt_total); + seq_printf(m, "%zu [%lu] gtt total\n", + dev_priv->gtt.total, + dev_priv->gtt.mappable_end - dev_priv->gtt.start); mutex_unlock(&dev->struct_mutex); @@ -384,7 +387,7 @@ static void i915_ring_seqno_info(struct seq_file *m, struct intel_ring_buffer *ring) { if (ring->get_seqno) { - seq_printf(m, "Current sequence (%s): %d\n", + seq_printf(m, "Current sequence (%s): %u\n", ring->name, ring->get_seqno(ring, false)); } } @@ -541,11 +544,11 @@ static int i915_hws_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; - const volatile u32 __iomem *hws; + const u32 *hws; int i; ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; - hws = (volatile u32 __iomem *)ring->status_page.page_addr; + hws = ring->status_page.page_addr; if (hws == NULL) return 0; @@ -605,7 +608,7 @@ static void print_error_buffers(struct seq_file *m, seq_printf(m, "%s [%d]:\n", name, count); while (count--) { - seq_printf(m, " %08x %8u %04x %04x %x %x%s%s%s%s%s%s%s", + seq_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s", err->gtt_offset, err->size, err->read_domains, @@ -812,11 +815,11 @@ static int i915_error_state_open(struct inode *inode, struct file *file) error_priv->dev = dev; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error_priv->error = dev_priv->first_error; + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error_priv->error = dev_priv->gpu_error.first_error; if (error_priv->error) kref_get(&error_priv->error->ref); - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); return single_open(file, i915_error_state, error_priv); } @@ -842,6 +845,77 @@ static const struct file_operations i915_error_state_fops = { .release = i915_error_state_release, }; +static ssize_t +i915_next_seqno_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + drm_i915_private_t *dev_priv = dev->dev_private; + char buf[80]; + int len; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + len = snprintf(buf, sizeof(buf), + "next_seqno : 0x%x\n", + dev_priv->next_seqno); + + mutex_unlock(&dev->struct_mutex); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_next_seqno_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + char buf[20]; + u32 val = 1; + int ret; + + if (cnt > 0) { + if (cnt > sizeof(buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + ret = kstrtouint(buf, 0, &val); + if (ret < 0) + return ret; + } + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + ret = i915_gem_set_seqno(dev, val); + + mutex_unlock(&dev->struct_mutex); + + return ret ?: cnt; +} + +static const struct file_operations i915_next_seqno_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = i915_next_seqno_read, + .write = i915_next_seqno_write, + .llseek = default_llseek, +}; + static int i915_rstdby_delays(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *) m->private; @@ -1372,28 +1446,31 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) ifbdev = dev_priv->fbdev; fb = to_intel_framebuffer(ifbdev->helper.fb); - seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ", + seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ", fb->base.width, fb->base.height, fb->base.depth, - fb->base.bits_per_pixel); + fb->base.bits_per_pixel, + atomic_read(&fb->base.refcount.refcount)); describe_obj(m, fb->obj); seq_printf(m, "\n"); + mutex_unlock(&dev->mode_config.mutex); + mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { if (&fb->base == ifbdev->helper.fb) continue; - seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ", + seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ", fb->base.width, fb->base.height, fb->base.depth, - fb->base.bits_per_pixel); + fb->base.bits_per_pixel, + atomic_read(&fb->base.refcount.refcount)); describe_obj(m, fb->obj); seq_printf(m, "\n"); } - - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.fb_lock); return 0; } @@ -1403,7 +1480,8 @@ static int i915_context_status(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + struct intel_ring_buffer *ring; + int ret, i; ret = mutex_lock_interruptible(&dev->mode_config.mutex); if (ret) @@ -1421,6 +1499,14 @@ static int i915_context_status(struct seq_file *m, void *unused) seq_printf(m, "\n"); } + for_each_ring(ring, dev_priv, i) { + if (ring->default_context) { + seq_printf(m, "HW default context %s ring ", ring->name); + describe_obj(m, ring->default_context->obj); + seq_printf(m, "\n"); + } + } + mutex_unlock(&dev->mode_config.mutex); return 0; @@ -1460,7 +1546,7 @@ static const char *swizzle_string(unsigned swizzle) case I915_BIT_6_SWIZZLE_9_10_17: return "bit9/bit10/bit17"; case I915_BIT_6_SWIZZLE_UNKNOWN: - return "unkown"; + return "unknown"; } return "bug"; @@ -1556,7 +1642,7 @@ static int i915_dpio_info(struct seq_file *m, void *data) return 0; } - ret = mutex_lock_interruptible(&dev->mode_config.mutex); + ret = mutex_lock_interruptible(&dev_priv->dpio_lock); if (ret) return ret; @@ -1585,7 +1671,7 @@ static int i915_dpio_info(struct seq_file *m, void *data) seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n", intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE)); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev_priv->dpio_lock); return 0; } @@ -1603,7 +1689,7 @@ i915_wedged_read(struct file *filp, len = snprintf(buf, sizeof(buf), "wedged : %d\n", - atomic_read(&dev_priv->mm.wedged)); + atomic_read(&dev_priv->gpu_error.reset_counter)); if (len > sizeof(buf)) len = sizeof(buf); @@ -1658,7 +1744,7 @@ i915_ring_stop_read(struct file *filp, int len; len = snprintf(buf, sizeof(buf), - "0x%08x\n", dev_priv->stop_rings); + "0x%08x\n", dev_priv->gpu_error.stop_rings); if (len > sizeof(buf)) len = sizeof(buf); @@ -1694,7 +1780,7 @@ i915_ring_stop_write(struct file *filp, if (ret) return ret; - dev_priv->stop_rings = val; + dev_priv->gpu_error.stop_rings = val; mutex_unlock(&dev->struct_mutex); return cnt; @@ -1708,6 +1794,102 @@ static const struct file_operations i915_ring_stop_fops = { .llseek = default_llseek, }; +#define DROP_UNBOUND 0x1 +#define DROP_BOUND 0x2 +#define DROP_RETIRE 0x4 +#define DROP_ACTIVE 0x8 +#define DROP_ALL (DROP_UNBOUND | \ + DROP_BOUND | \ + DROP_RETIRE | \ + DROP_ACTIVE) +static ssize_t +i915_drop_caches_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + char buf[20]; + int len; + + len = snprintf(buf, sizeof(buf), "0x%08x\n", DROP_ALL); + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_drop_caches_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *obj, *next; + char buf[20]; + int val = 0, ret; + + if (cnt > 0) { + if (cnt > sizeof(buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtoul(buf, NULL, 0); + } + + DRM_DEBUG_DRIVER("Dropping caches: 0x%08x\n", val); + + /* No need to check and wait for gpu resets, only libdrm auto-restarts + * on ioctls on -EAGAIN. */ + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + if (val & DROP_ACTIVE) { + ret = i915_gpu_idle(dev); + if (ret) + goto unlock; + } + + if (val & (DROP_RETIRE | DROP_ACTIVE)) + i915_gem_retire_requests(dev); + + if (val & DROP_BOUND) { + list_for_each_entry_safe(obj, next, &dev_priv->mm.inactive_list, mm_list) + if (obj->pin_count == 0) { + ret = i915_gem_object_unbind(obj); + if (ret) + goto unlock; + } + } + + if (val & DROP_UNBOUND) { + list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list) + if (obj->pages_pin_count == 0) { + ret = i915_gem_object_put_pages(obj); + if (ret) + goto unlock; + } + } + +unlock: + mutex_unlock(&dev->struct_mutex); + + return ret ?: cnt; +} + +static const struct file_operations i915_drop_caches_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = i915_drop_caches_read, + .write = i915_drop_caches_write, + .llseek = default_llseek, +}; + static ssize_t i915_max_freq_read(struct file *filp, char __user *ubuf, @@ -2104,12 +2286,24 @@ int i915_debugfs_init(struct drm_minor *minor) if (ret) return ret; + ret = i915_debugfs_create(minor->debugfs_root, minor, + "i915_gem_drop_caches", + &i915_drop_caches_fops); + if (ret) + return ret; + ret = i915_debugfs_create(minor->debugfs_root, minor, "i915_error_state", &i915_error_state_fops); if (ret) return ret; + ret = i915_debugfs_create(minor->debugfs_root, minor, + "i915_next_seqno", + &i915_next_seqno_fops); + if (ret) + return ret; + return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, minor->debugfs_root, minor); @@ -2129,10 +2323,14 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_drop_caches_fops, + 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops, 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_error_state_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_next_seqno_fops, + 1, minor); } #endif /* CONFIG_DEBUG_FS */ diff --git a/sys/dev/drm/i915/i915_dma.c b/sys/dev/drm/i915/i915_dma.c index 73d76e6629..c696eeae10 100644 --- a/sys/dev/drm/i915/i915_dma.c +++ b/sys/dev/drm/i915/i915_dma.c @@ -162,10 +162,10 @@ static int i915_dma_cleanup(struct drm_device * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); for (i = 0; i < I915_NUM_RINGS; i++) intel_cleanup_ring_buffer(&dev_priv->ring[i]); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); /* Clear the HWS virtual address at teardown */ if (I915_NEED_GFX_HWS(dev)) @@ -601,9 +601,9 @@ static int i915_flush_ioctl(struct drm_device *dev, void *data, RING_LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); ret = i915_quiescent(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -649,9 +649,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, } } - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); ret = i915_dispatch_batchbuffer(dev, batch, cliprects); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); if (sarea_priv) sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -710,9 +710,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, } } - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); ret = i915_dispatch_cmdbuffer(dev, cmdbuf, cliprects, batch_data); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); if (ret) { DRM_ERROR("i915_dispatch_cmdbuffer failed\n"); goto fail_clip_free; @@ -824,9 +824,9 @@ static int i915_irq_emit(struct drm_device *dev, void *data, RING_LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); result = i915_emit_irq(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) { DRM_ERROR("copy_to_user\n"); @@ -909,9 +909,9 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, RING_LOCK_TEST_WITH_RETURN(dev, file_priv); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); ret = i915_dispatch_flip(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -993,6 +993,12 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_PINNED_BATCHES: value = 1; break; + case I915_PARAM_HAS_EXEC_NO_RELOC: + value = 1; + break; + case I915_PARAM_HAS_EXEC_HANDLE_LUT: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); @@ -1024,7 +1030,7 @@ static int i915_setparam(struct drm_device *dev, void *data, case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY: break; case I915_SETPARAM_ALLOW_BATCHBUFFER: - dev_priv->dri1.allow_batchbuffer = param->value; + dev_priv->dri1.allow_batchbuffer = param->value ? 1 : 0; break; case I915_SETPARAM_NUM_USED_FENCES: if (param->value > dev_priv->num_fence_regs || @@ -1072,7 +1078,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12); dev_priv->dri1.gfx_hws_cpu_addr = - ioremap_wc(dev_priv->mm.gtt_base_addr + hws->addr, 4096); + ioremap_wc(dev_priv->gtt.mappable_base + hws->addr, 4096); if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) { i915_dma_cleanup(dev); ring->status_page.gfx_addr = 0; @@ -1260,17 +1266,23 @@ static int i915_load_modeset_init(struct drm_device *dev) goto cleanup_vga_switcheroo; #endif + ret = drm_irq_install(dev); + if (ret) + goto cleanup_gem_stolen; + + /* Important: The output setup functions called by modeset_init need + * working irqs for e.g. gmbus and dp aux transfers. */ intel_modeset_init(dev); ret = i915_gem_init(dev); if (ret) - goto cleanup_gem_stolen; + goto cleanup_irq; - intel_modeset_gem_init(dev); +#if 0 + INIT_WORK(&dev_priv->console_resume_work, intel_console_resume); +#endif - ret = drm_irq_install(dev); - if (ret) - goto cleanup_gem; + intel_modeset_gem_init(dev); /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ @@ -1278,7 +1290,25 @@ static int i915_load_modeset_init(struct drm_device *dev) ret = intel_fbdev_init(dev); if (ret) - goto cleanup_irq; + goto cleanup_gem; + + /* Only enable hotplug handling once the fbdev is fully set up. */ + intel_hpd_init(dev); + + /* + * Some ports require correctly set-up hpd registers for detection to + * work properly (leading to ghost connected connector status), e.g. VGA + * on gm45. Hence we can only set up the initial fbdev config after hpd + * irqs are fully enabled. Now we should scan for the initial config + * only once hotplug handling is enabled, but due to screwed-up locking + * around kms/fbdev init we can't protect the fdbev initial config + * scanning against hotplug events. Hence do this first and ignore the + * tiny window where we will loose hotplug notifactions. + */ + intel_fbdev_initial_config(dev); + + /* Only enable hotplug handling once the fbdev is fully set up. */ + dev_priv->enable_hotplug_processing = true; drm_kms_helper_poll_init(dev); @@ -1287,13 +1317,13 @@ static int i915_load_modeset_init(struct drm_device *dev) return 0; -cleanup_irq: - drm_irq_uninstall(dev); cleanup_gem: - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_aliasing_ppgtt(dev); +cleanup_irq: + drm_irq_uninstall(dev); cleanup_gem_stolen: #if 0 i915_gem_cleanup_stolen(dev); @@ -1306,6 +1336,29 @@ out: return ret; } +#if 0 +static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv) +{ + struct apertures_struct *ap; + struct pci_dev *pdev = dev_priv->dev->pdev; + bool primary; + + ap = alloc_apertures(1); + if (!ap) + return; + + ap->ranges[0].base = dev_priv->gtt.mappable_base; + ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start; + + primary = + pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; + + remove_conflicting_framebuffers(ap, "inteldrmfb", primary); + + kfree(ap); +} +#endif + /** * i915_driver_load - setup chip and create an initial config * @dev: DRM device @@ -1321,11 +1374,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long base, size; - int mmio_bar, ret; + int ret = 0, mmio_bar; static struct pci_dev i915_pdev; - ret = 0; - /* XXX: struct pci_dev */ i915_pdev.dev = dev->dev; dev->pdev = &i915_pdev; @@ -1347,16 +1398,71 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev_priv->info = i915_get_device_id(dev->pci_device); if (i915_get_bridge_dev(dev)) { - drm_free(dev_priv, M_DRM); - return (-EIO); + ret = -EIO; + goto free_priv; } ret = i915_gem_gtt_init(dev); if (ret) goto put_bridge; - /* Add register map (needed for suspend/resume) */ +#if 0 + if (drm_core_check_feature(dev, DRIVER_MODESET)) + i915_kick_out_firmware_fb(dev_priv); + + pci_set_master(dev->pdev); + + /* overlay on gen2 is broken and can't address above 1G */ + if (IS_GEN2(dev)) + dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(30)); + + /* 965GM sometimes incorrectly writes to hardware status page (HWS) + * using 32bit addressing, overwriting memory if HWS is located + * above 4GB. + * + * The documentation also mentions an issue with undefined + * behaviour if any general state is accessed within a page above 4GB, + * which also needs to be handled carefully. + */ + if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) + dma_set_coherent_mask(&dev->pdev->dev, DMA_BIT_MASK(32)); +#endif + mmio_bar = IS_GEN2(dev) ? 1 : 0; + /* Before gen4, the registers and the GTT are behind different BARs. + * However, from gen4 onwards, the registers and the GTT are shared + * in the same BAR, so we want to restrict this ioremap from + * clobbering the GTT which we want ioremap_wc instead. Fortunately, + * the register BAR remains the same size for all the earlier + * generations up to Ironlake. + */ +#if 0 + if (info->gen < 5) + mmio_size = 512*1024; + else + mmio_size = 2*1024*1024; + + dev_priv->regs = pci_iomap(dev->pdev, mmio_bar, mmio_size); + if (!dev_priv->regs) { + DRM_ERROR("failed to map registers\n"); + ret = -EIO; + goto put_gmch; + } + + aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + + dev_priv->gtt.mappable = + io_mapping_create_wc(dev_priv->gtt.mappable_base, + aperture_size); + if (dev_priv->gtt.mappable == NULL) { + ret = -EIO; + goto out_rmmap; + } + + i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base, + aperture_size); +#endif + base = drm_get_resource_start(dev, mmio_bar); size = drm_get_resource_len(dev, mmio_bar); @@ -1409,13 +1515,18 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) * be lost or delayed, but we use them anyways to avoid * stuck interrupts on some machines. */ +#if 0 + if (!IS_I945G(dev) && !IS_I945GM(dev)) + pci_enable_msi(dev->pdev); +#endif lockinit(&dev_priv->irq_lock, "userirq", 0, LK_CANRECURSE); - lockinit(&dev_priv->error_lock, "915err", 0, LK_CANRECURSE); + lockinit(&dev_priv->gpu_error.lock, "915err", 0, LK_CANRECURSE); spin_init(&dev_priv->rps.lock, "i915initrps"); - spin_init(&dev_priv->dpio_lock, "i915initdpio"); + lockinit(&dev_priv->dpio_lock, "i915dpio", 0, LK_CANRECURSE); lockinit(&dev_priv->rps.hw_lock, "i915 rps.hw_lock", 0, LK_CANRECURSE); + lockinit(&dev_priv->modeset_restore_lock, "i915mrl", 0, LK_CANRECURSE); if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) dev_priv->num_pipe = 3; @@ -1439,11 +1550,15 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } } +#if 0 + i915_setup_sysfs(dev); +#endif + /* Must be done after probing outputs */ intel_opregion_init(dev); - - setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed, - (unsigned long) dev); +#if 0 + acpi_video_register(); +#endif if (IS_GEN5(dev)) intel_gpu_ips_init(dev_priv); @@ -1451,11 +1566,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) return 0; out_gem_unload: + intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); destroy_workqueue(dev_priv->wq); out_mtrrfree: put_bridge: +free_priv: + kfree(dev_priv, M_DRM); return ret; } @@ -1466,28 +1584,57 @@ int i915_driver_unload(struct drm_device *dev) intel_gpu_ips_teardown(); - DRM_LOCK(dev); +#if 0 + i915_teardown_sysfs(dev); + + if (dev_priv->mm.inactive_shrinker.shrink) + unregister_shrinker(&dev_priv->mm.inactive_shrinker); +#endif + + mutex_lock(&dev->struct_mutex); ret = i915_gpu_idle(dev); if (ret) DRM_ERROR("failed to idle hardware: %d\n", ret); i915_gem_retire_requests(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); /* Cancel the retire work handler, which should be idle now. */ cancel_delayed_work_sync(&dev_priv->mm.retire_work); - i915_free_hws(dev); +#if 0 + io_mapping_free(dev_priv->gtt.mappable); + if (dev_priv->mm.gtt_mtrr >= 0) { + mtrr_del(dev_priv->mm.gtt_mtrr, + dev_priv->gtt.mappable_base, + dev_priv->mm.gtt->gtt_mappable_entries * PAGE_SIZE); + dev_priv->mm.gtt_mtrr = -1; + } - intel_teardown_mchbar(dev); + acpi_video_unregister(); +#endif if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_fbdev_fini(dev); intel_modeset_cleanup(dev); +#if 0 + cancel_work_sync(&dev_priv->console_resume_work); +#endif + + /* + * free the memory space allocated for the child device + * config parsed from VBT + */ + if (dev_priv->child_dev && dev_priv->child_dev_num) { + kfree(dev_priv->child_dev, M_DRM); + dev_priv->child_dev = NULL; + dev_priv->child_dev_num = 0; + } + } /* Free error state after interrupts are fully disabled. */ - del_timer_sync(&dev_priv->hangcheck_timer); - cancel_work_sync(&dev_priv->error_work); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); + cancel_work_sync(&dev_priv->gpu_error.work); i915_destroy_error_state(dev); intel_opregion_fini(dev); @@ -1496,28 +1643,36 @@ int i915_driver_unload(struct drm_device *dev) /* Flush any outstanding unpin_work. */ flush_workqueue(dev_priv->wq); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); i915_gem_free_all_phys_object(dev); i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); i915_gem_cleanup_aliasing_ppgtt(dev); - drm_mm_takedown(&dev_priv->mm.stolen); - - intel_cleanup_overlay(dev); +#if 0 + i915_gem_cleanup_stolen(dev); +#endif if (!I915_NEED_GFX_HWS(dev)) i915_free_hws(dev); } - i915_gem_unload(dev); +#if 0 + if (dev_priv->regs != NULL) + pci_iounmap(dev->pdev, dev_priv->regs); +#endif + + intel_teardown_gmbus(dev); + intel_teardown_mchbar(dev); bus_generic_detach(dev->dev); drm_rmmap(dev, dev_priv->mmio_map); intel_teardown_gmbus(dev); destroy_workqueue(dev_priv->wq); + pm_qos_remove_request(&dev_priv->pm_qos); + pci_dev_put(dev_priv->bridge_dev); drm_free(dev->dev_private, M_DRM); return 0; diff --git a/sys/dev/drm/i915/i915_drv.c b/sys/dev/drm/i915/i915_drv.c index 04eaaaf5dc..5f0aa603de 100644 --- a/sys/dev/drm/i915/i915_drv.c +++ b/sys/dev/drm/i915/i915_drv.c @@ -38,6 +38,18 @@ int i915_lvds_channel_mode __read_mostly = 0; TUNABLE_INT("drm.i915.lvds_channel_mode", &i915_lvds_channel_mode); +int i915_disable_power_well __read_mostly = 0; +module_param_named(disable_power_well, i915_disable_power_well, int, 0600); +MODULE_PARM_DESC(disable_power_well, + "Disable the power well when possible (default: false)"); + +bool i915_enable_hangcheck __read_mostly = true; +module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644); +MODULE_PARM_DESC(enable_hangcheck, + "Periodically check GPU activity for detecting hangs. " + "WARNING: Disabling this can cause system wide hangs. " + "(default: true)"); + static struct drm_driver driver; #define INTEL_VGA_DEVICE(id, info_) { \ @@ -184,6 +196,7 @@ static const struct intel_device_info intel_valleyview_m_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, }; static const struct intel_device_info intel_valleyview_d_info = { @@ -193,6 +206,7 @@ static const struct intel_device_info intel_valleyview_d_info = { .has_bsd_ring = 1, .has_blt_ring = 1, .is_valleyview = 1, + .display_mmio_offset = VLV_DISPLAY_BASE, }; static const struct intel_device_info intel_haswell_d_info = { @@ -263,40 +277,64 @@ static const struct intel_gfx_device_id { INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */ INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */ INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */ - INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT2 desktop */ + INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT3 desktop */ INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */ INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */ - INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT2 server */ + INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT3 server */ INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */ INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */ INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */ + INTEL_VGA_DEVICE(0x040B, &intel_haswell_d_info), /* GT1 reserved */ + INTEL_VGA_DEVICE(0x041B, &intel_haswell_d_info), /* GT2 reserved */ + INTEL_VGA_DEVICE(0x042B, &intel_haswell_d_info), /* GT3 reserved */ + INTEL_VGA_DEVICE(0x040E, &intel_haswell_d_info), /* GT1 reserved */ + INTEL_VGA_DEVICE(0x041E, &intel_haswell_d_info), /* GT2 reserved */ + INTEL_VGA_DEVICE(0x042E, &intel_haswell_d_info), /* GT3 reserved */ INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */ INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */ - INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT2 desktop */ + INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT3 desktop */ INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */ INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */ - INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT2 server */ + INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT3 server */ INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */ INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */ - INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT2 mobile */ + INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT3 mobile */ + INTEL_VGA_DEVICE(0x0C0B, &intel_haswell_d_info), /* SDV GT1 reserved */ + INTEL_VGA_DEVICE(0x0C1B, &intel_haswell_d_info), /* SDV GT2 reserved */ + INTEL_VGA_DEVICE(0x0C2B, &intel_haswell_d_info), /* SDV GT3 reserved */ + INTEL_VGA_DEVICE(0x0C0E, &intel_haswell_d_info), /* SDV GT1 reserved */ + INTEL_VGA_DEVICE(0x0C1E, &intel_haswell_d_info), /* SDV GT2 reserved */ + INTEL_VGA_DEVICE(0x0C2E, &intel_haswell_d_info), /* SDV GT3 reserved */ INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */ INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */ - INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT2 desktop */ + INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT3 desktop */ INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */ INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */ - INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT2 server */ + INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT3 server */ INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */ INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */ - INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */ + INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT3 mobile */ + INTEL_VGA_DEVICE(0x0A0B, &intel_haswell_d_info), /* ULT GT1 reserved */ + INTEL_VGA_DEVICE(0x0A1B, &intel_haswell_d_info), /* ULT GT2 reserved */ + INTEL_VGA_DEVICE(0x0A2B, &intel_haswell_d_info), /* ULT GT3 reserved */ + INTEL_VGA_DEVICE(0x0A0E, &intel_haswell_m_info), /* ULT GT1 reserved */ + INTEL_VGA_DEVICE(0x0A1E, &intel_haswell_m_info), /* ULT GT2 reserved */ + INTEL_VGA_DEVICE(0x0A2E, &intel_haswell_m_info), /* ULT GT3 reserved */ INTEL_VGA_DEVICE(0x0D02, &intel_haswell_d_info), /* CRW GT1 desktop */ INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT2 desktop */ - INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */ + INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT3 desktop */ INTEL_VGA_DEVICE(0x0D0A, &intel_haswell_d_info), /* CRW GT1 server */ INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT2 server */ - INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */ + INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT3 server */ INTEL_VGA_DEVICE(0x0D06, &intel_haswell_m_info), /* CRW GT1 mobile */ INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */ - INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */ + INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT3 mobile */ + INTEL_VGA_DEVICE(0x0D0B, &intel_haswell_d_info), /* CRW GT1 reserved */ + INTEL_VGA_DEVICE(0x0D1B, &intel_haswell_d_info), /* CRW GT2 reserved */ + INTEL_VGA_DEVICE(0x0D2B, &intel_haswell_d_info), /* CRW GT3 reserved */ + INTEL_VGA_DEVICE(0x0D0E, &intel_haswell_d_info), /* CRW GT1 reserved */ + INTEL_VGA_DEVICE(0x0D1E, &intel_haswell_d_info), /* CRW GT2 reserved */ + INTEL_VGA_DEVICE(0x0D2E, &intel_haswell_d_info), /* CRW GT3 reserved */ INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info), INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info), @@ -379,6 +417,13 @@ static int i915_drm_freeze(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + /* ignore lid events during suspend */ + mutex_lock(&dev_priv->modeset_restore_lock); + dev_priv->modeset_restore = MODESET_SUSPENDED; + mutex_unlock(&dev_priv->modeset_restore_lock); + + intel_set_power_well(dev, true); + drm_kms_helper_poll_disable(dev); #if 0 @@ -389,10 +434,11 @@ static int i915_drm_freeze(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { int error = i915_gem_idle(dev); if (error) { - device_printf(dev->dev, - "GEM idle failed, resume might fail"); + dev_err(dev->pdev->dev, + "GEM idle failed, resume might fail\n"); return error; } + cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); #if 0 @@ -400,15 +446,13 @@ static int i915_drm_freeze(struct drm_device *dev) #endif drm_irq_uninstall(dev); + dev_priv->enable_hotplug_processing = false; } i915_save_state(dev); intel_opregion_fini(dev); - /* Modeset on resume, not lid events */ - dev_priv->modeset_on_lid = 0; - return 0; } @@ -434,19 +478,11 @@ i915_suspend(device_t kdev) return (error); } -static int i915_drm_thaw(struct drm_device *dev) +static int __i915_drm_thaw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int error = 0; - intel_gt_reset(dev); - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - DRM_LOCK(dev); - i915_gem_restore_gtt_mappings(dev); - DRM_UNLOCK(dev); - } - i915_restore_state(dev); intel_opregion_setup(dev); @@ -454,26 +490,64 @@ static int i915_drm_thaw(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) { intel_init_pch_refclk(dev); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); dev_priv->mm.suspended = 0; error = i915_gem_init_hw(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); + + /* We need working interrupts for modeset enabling ... */ + drm_irq_install(dev); intel_modeset_init_hw(dev); intel_modeset_setup_hw_state(dev, false); - drm_irq_install(dev); + + /* + * ... but also need to make sure that hotplug processing + * doesn't cause havoc. Like in the driver load code we don't + * bother with the tiny race here where we might loose hotplug + * notifications. + * */ + intel_hpd_init(dev); + dev_priv->enable_hotplug_processing = true; } intel_opregion_init(dev); - dev_priv->modeset_on_lid = 0; - + /* + * The console lock can be pretty contented on resume due + * to all the printk activity. Try to keep it out of the hot + * path of resume if possible. + */ #if 0 - console_lock(); - intel_fbdev_set_suspend(dev, 0); - console_unlock(); + if (console_trylock()) { + intel_fbdev_set_suspend(dev, 0); + console_unlock(); + } else { + schedule_work(&dev_priv->console_resume_work); + } #endif + + mutex_lock(&dev_priv->modeset_restore_lock); + dev_priv->modeset_restore = MODESET_DONE; + mutex_unlock(&dev_priv->modeset_restore_lock); + return error; +} + +static int i915_drm_thaw(struct drm_device *dev) +{ + int error = 0; + + intel_gt_reset(dev); + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + mutex_lock(&dev->struct_mutex); + i915_gem_restore_gtt_mappings(dev); + mutex_unlock(&dev->struct_mutex); + } + + __i915_drm_thaw(dev); + return error; } @@ -509,29 +583,6 @@ static drm_pci_id_list_t i915_attach_list[] = { {0, 0, 0, NULL} }; -static int -i915_probe(device_t kdev) -{ - int device, i = 0; - - if (pci_get_class(kdev) != PCIC_DISPLAY) - return ENXIO; - - if (pci_get_vendor(kdev) != PCI_VENDOR_INTEL) - return ENXIO; - - device = pci_get_device(kdev); - - for (i = 0; pciidlist[i].device != 0; i++) { - if (pciidlist[i].device == device) { - i915_attach_list[0].device = device; - return 0; - } - } - - return ENXIO; -} - int i915_modeset; /* static int __init i915_init(void) */ @@ -564,30 +615,7 @@ i915_get_device_id(int device) return (NULL); } -static device_method_t i915_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, i915_probe), - DEVMETHOD(device_attach, i915_attach), - DEVMETHOD(device_suspend, i915_suspend), - DEVMETHOD(device_resume, i915_resume), - DEVMETHOD(device_detach, drm_detach), - DEVMETHOD_END -}; - -static driver_t i915_driver = { - "drm", - i915_methods, - sizeof(struct drm_device) -}; - extern devclass_t drm_devclass; -DRIVER_MODULE_ORDERED(i915kms, vgapci, i915_driver, drm_devclass, 0, 0, - SI_ORDER_ANY); -MODULE_DEPEND(i915kms, drm, 1, 1, 1); -MODULE_DEPEND(i915kms, agp, 1, 1, 1); -MODULE_DEPEND(i915kms, iicbus, 1, 1, 1); -MODULE_DEPEND(i915kms, iic, 1, 1, 1); -MODULE_DEPEND(i915kms, iicbb, 1, 1, 1); int intel_iommu_enabled = 0; TUNABLE_INT("drm.i915.intel_iommu_enabled", &intel_iommu_enabled); @@ -614,8 +642,6 @@ int i915_modeset = 1; TUNABLE_INT("drm.i915.modeset", &i915_modeset); int i915_enable_ppgtt = -1; TUNABLE_INT("drm.i915.enable_ppgtt", &i915_enable_ppgtt); -int i915_enable_hangcheck = 1; -TUNABLE_INT("drm.i915.enable_hangcheck", &i915_enable_hangcheck); static int i8xx_do_reset(struct drm_device *dev) { @@ -759,9 +785,9 @@ int intel_gpu_reset(struct drm_device *dev) } /* Also reset the gpu hangman. */ - if (dev_priv->stop_rings) { + if (dev_priv->gpu_error.stop_rings) { DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n"); - dev_priv->stop_rings = 0; + dev_priv->gpu_error.stop_rings = 0; if (ret == -ENODEV) { DRM_ERROR("Reset not implemented, but ignoring " "error for simulated gpu hangs\n"); @@ -795,20 +821,20 @@ int i915_reset(struct drm_device *dev) if (!i915_try_reset) return 0; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); i915_gem_reset(dev); ret = -ENODEV; - if (time_uptime - dev_priv->last_gpu_reset < 5) + if (time_uptime - dev_priv->gpu_error.last_reset < 5) DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); else ret = intel_gpu_reset(dev); - dev_priv->last_gpu_reset = time_uptime; + dev_priv->gpu_error.last_reset = time_uptime; if (ret) { DRM_ERROR("Failed to reset chip.\n"); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -847,17 +873,41 @@ int i915_reset(struct drm_device *dev) * some unknown reason, this blows up my ilk, so don't. */ - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); drm_irq_install(dev); + intel_hpd_init(dev); } else { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } return 0; } +static int +i915_pci_probe(device_t kdev) +{ + int device, i = 0; + + if (pci_get_class(kdev) != PCIC_DISPLAY) + return ENXIO; + + if (pci_get_vendor(kdev) != PCI_VENDOR_INTEL) + return ENXIO; + + device = pci_get_device(kdev); + + for (i = 0; pciidlist[i].device != 0; i++) { + if (pciidlist[i].device == device) { + i915_attach_list[0].device = device; + return 0; + } + } + + return ENXIO; +} + static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ | DRIVER_LOCKLESS_IRQ | @@ -888,107 +938,35 @@ static struct drm_driver driver = { .patchlevel = DRIVER_PATCHLEVEL, }; +static device_method_t i915_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, i915_pci_probe), + DEVMETHOD(device_attach, i915_attach), + DEVMETHOD(device_suspend, i915_suspend), + DEVMETHOD(device_resume, i915_resume), + DEVMETHOD(device_detach, drm_detach), + DEVMETHOD_END +}; + +static driver_t i915_driver = { + "drm", + i915_methods, + sizeof(struct drm_device) +}; + +DRIVER_MODULE_ORDERED(i915kms, vgapci, i915_driver, drm_devclass, 0, 0, + SI_ORDER_ANY); +MODULE_DEPEND(i915kms, drm, 1, 1, 1); +MODULE_DEPEND(i915kms, agp, 1, 1, 1); +MODULE_DEPEND(i915kms, iicbus, 1, 1, 1); +MODULE_DEPEND(i915kms, iic, 1, 1, 1); +MODULE_DEPEND(i915kms, iicbb, 1, 1, 1); + /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ ((HAS_FORCE_WAKE((dev_priv)->dev)) && \ ((reg) < 0x40000) && \ ((reg) != FORCEWAKE)) - -static bool IS_DISPLAYREG(u32 reg) -{ - /* - * This should make it easier to transition modules over to the - * new register block scheme, since we can do it incrementally. - */ - if (reg >= VLV_DISPLAY_BASE) - return false; - - if (reg >= RENDER_RING_BASE && - reg < RENDER_RING_BASE + 0xff) - return false; - if (reg >= GEN6_BSD_RING_BASE && - reg < GEN6_BSD_RING_BASE + 0xff) - return false; - if (reg >= BLT_RING_BASE && - reg < BLT_RING_BASE + 0xff) - return false; - - if (reg == PGTBL_ER) - return false; - - if (reg >= IPEIR_I965 && - reg < HWSTAM) - return false; - - if (reg == MI_MODE) - return false; - - if (reg == GFX_MODE_GEN7) - return false; - - if (reg == RENDER_HWS_PGA_GEN7 || - reg == BSD_HWS_PGA_GEN7 || - reg == BLT_HWS_PGA_GEN7) - return false; - - if (reg == GEN6_BSD_SLEEP_PSMI_CONTROL || - reg == GEN6_BSD_RNCID) - return false; - - if (reg == GEN6_BLITTER_ECOSKPD) - return false; - - if (reg >= 0x4000c && - reg <= 0x4002c) - return false; - - if (reg >= 0x4f000 && - reg <= 0x4f08f) - return false; - - if (reg >= 0x4f100 && - reg <= 0x4f11f) - return false; - - if (reg >= VLV_MASTER_IER && - reg <= GEN6_PMIER) - return false; - - if (reg >= FENCE_REG_SANDYBRIDGE_0 && - reg < (FENCE_REG_SANDYBRIDGE_0 + (16*8))) - return false; - - if (reg >= VLV_IIR_RW && - reg <= VLV_ISR) - return false; - - if (reg == FORCEWAKE_VLV || - reg == FORCEWAKE_ACK_VLV) - return false; - - if (reg == GEN6_GDRST) - return false; - - switch (reg) { - case _3D_CHICKEN3: - case IVB_CHICKEN3: - case GEN7_COMMON_SLICE_CHICKEN1: - case GEN7_L3CNTLREG1: - case GEN7_L3_CHICKEN_MODE_REGISTER: - case GEN7_ROW_CHICKEN2: - case GEN7_L3SQCREG4: - case GEN7_SQ_CHICKEN_MBCUNIT_CONFIG: - case GEN7_HALF_SLICE_CHICKEN1: - case GEN6_MBCTL: - case GEN6_UCGCTL2: - return false; - default: - break; - } - - return true; -} - static void ilk_dummy_write(struct drm_i915_private *dev_priv) { @@ -1011,8 +989,6 @@ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ if (dev_priv->forcewake_count == 0) \ dev_priv->gt.force_wake_put(dev_priv); \ lockmgr(&dev_priv->gt_lock, LK_RELEASE); \ - } else if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ - val = DRM_READ##y(dev_priv->mmio_map, reg + 0x180000); \ } else { \ val = DRM_READ##y(dev_priv->mmio_map, reg); \ } \ @@ -1039,11 +1015,7 @@ void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ DRM_ERROR("Unknown unclaimed register before writing to %x\n", reg); \ I915_WRITE_NOTRACE(GEN7_ERR_INT, ERR_INT_MMIO_UNCLAIMED); \ } \ - if (IS_VALLEYVIEW(dev_priv->dev) && IS_DISPLAYREG(reg)) { \ - DRM_WRITE##y(dev_priv->mmio_map, reg + 0x180000, val); \ - } else { \ - DRM_WRITE##y(dev_priv->mmio_map, reg, val); \ - } \ + DRM_WRITE##y(dev_priv->mmio_map, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ diff --git a/sys/dev/drm/i915/i915_drv.h b/sys/dev/drm/i915/i915_drv.h index d6d2db2046..8a8f427a49 100644 --- a/sys/dev/drm/i915/i915_drv.h +++ b/sys/dev/drm/i915/i915_drv.h @@ -30,14 +30,15 @@ #ifndef _I915_DRV_H_ #define _I915_DRV_H_ +#include + #include "i915_reg.h" #include "intel_bios.h" #include "intel_ringbuffer.h" -#include #include #include #include -#include +#include #define CONFIG_ACPI 1 @@ -83,7 +84,12 @@ enum port { }; #define port_name(p) ((p) + 'A') -#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) +#define I915_GEM_GPU_DOMAINS \ + (I915_GEM_DOMAIN_RENDER | \ + I915_GEM_DOMAIN_SAMPLER | \ + I915_GEM_DOMAIN_COMMAND | \ + I915_GEM_DOMAIN_INSTRUCTION | \ + I915_GEM_DOMAIN_VERTEX) #define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) @@ -101,6 +107,19 @@ struct intel_pch_pll { }; #define I915_NUM_PLLS 2 +/* Used by dp and fdi links */ +struct intel_link_m_n { + uint32_t tu; + uint32_t gmch_m; + uint32_t gmch_n; + uint32_t link_m; + uint32_t link_n; +}; + +void intel_link_compute_m_n(int bpp, int nlanes, + int pixel_clock, int link_clock, + struct intel_link_m_n *m_n); + struct intel_ddi_plls { int spll_refcount; int wrpll1_refcount; @@ -132,6 +151,7 @@ struct intel_ddi_plls { struct drm_i915_gem_phys_object { int id; + struct page **page_list; drm_dma_handle_t *handle; struct drm_i915_gem_object *cur_obj; }; @@ -278,6 +298,7 @@ struct drm_i915_display_funcs { struct drm_i915_gem_object *obj); int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y); + void (*hpd_irq_setup)(struct drm_device *dev); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -317,6 +338,7 @@ struct drm_i915_gt_funcs { DEV_INFO_FLAG(has_llc) struct intel_device_info { + u32 display_mmio_offset; u8 gen; u8 is_mobile:1; u8 is_i85x:1; @@ -344,6 +366,50 @@ struct intel_device_info { u8 has_llc:1; }; +enum i915_cache_level { + I915_CACHE_NONE = 0, + I915_CACHE_LLC, + I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ +}; + +/* The Graphics Translation Table is the way in which GEN hardware translates a + * Graphics Virtual Address into a Physical Address. In addition to the normal + * collateral associated with any va->pa translations GEN hardware also has a + * portion of the GTT which can be mapped by the CPU and remain both coherent + * and correct (in cases like swizzling). That region is referred to as GMADR in + * the spec. + */ +struct i915_gtt { + unsigned long start; /* Start offset of used GTT */ + size_t total; /* Total size GTT can map */ + size_t stolen_size; /* Total size of stolen memory */ + + unsigned long mappable_end; /* End offset that we can CPU map */ + struct io_mapping *mappable; /* Mapping to our CPU mappable region */ + phys_addr_t mappable_base; /* PA of our GMADR */ + + /** "Graphics Stolen Memory" holds the global PTEs */ + void __iomem *gsm; + + bool do_idle_maps; + dma_addr_t scratch_page_dma; + struct page *scratch_page; + + /* global gtt ops */ + int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, + size_t *stolen, phys_addr_t *mappable_base, + unsigned long *mappable_end); + void (*gtt_remove)(struct drm_device *dev); + void (*gtt_clear_range)(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries); + void (*gtt_insert_entries)(struct drm_device *dev, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level); +}; +#define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT) + #define I915_PPGTT_PD_ENTRIES 512 #define I915_PPGTT_PT_ENTRIES 1024 struct i915_hw_ppgtt { @@ -351,8 +417,18 @@ struct i915_hw_ppgtt { unsigned num_pd_entries; vm_page_t *pt_pages; uint32_t pd_offset; - vm_paddr_t *pt_dma_addr; - vm_paddr_t scratch_page_dma_addr; + dma_addr_t *pt_dma_addr; + dma_addr_t scratch_page_dma_addr; + + /* pte functions, mirroring the interface of the global gtt. */ + void (*clear_range)(struct i915_hw_ppgtt *ppgtt, + unsigned int first_entry, + unsigned int num_entries); + void (*insert_entries)(struct i915_hw_ppgtt *ppgtt, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level); + void (*cleanup)(struct i915_hw_ppgtt *ppgtt); }; @@ -586,6 +662,9 @@ struct intel_gen6_power_mgmt { struct lock hw_lock; }; +/* defined intel_pm.c */ +extern struct lock mchdev_lock; + struct intel_ilk_power_mgmt { u8 cur_delay; u8 min_delay; @@ -626,8 +705,164 @@ struct intel_l3_parity { struct work_struct error_work; }; +struct i915_gem_mm { + /** Bridge to intel-gtt-ko */ + struct intel_gtt *gtt; + /** Memory allocator for GTT stolen memory */ + struct drm_mm stolen; + /** Memory allocator for GTT */ + struct drm_mm gtt_space; + /** List of all objects in gtt_space. Used to restore gtt + * mappings on resume */ + struct list_head bound_list; + /** + * List of objects which are not bound to the GTT (thus + * are idle and not used by the GPU) but still have + * (presumably uncached) pages still attached. + */ + struct list_head unbound_list; + + /** Usable portion of the GTT for GEM */ + unsigned long stolen_base; /* limited to low memory (32-bit) */ + + int gtt_mtrr; + + /** PPGTT used for aliasing the PPGTT with the GTT */ + struct i915_hw_ppgtt *aliasing_ppgtt; + + eventhandler_tag inactive_shrinker; + bool shrinker_no_lock_stealing; + + /** + * List of objects currently involved in rendering. + * + * Includes buffers having the contents of their GPU caches + * flushed, not necessarily primitives. last_rendering_seqno + * represents when the rendering involved will be completed. + * + * A reference is held on the buffer while on this list. + */ + struct list_head active_list; + + /** + * LRU list of objects which are not in the ringbuffer and + * are ready to unbind, but are still in the GTT. + * + * last_rendering_seqno is 0 while an object is in this list. + * + * A reference is not held on the buffer while on this list, + * as merely being GTT-bound shouldn't prevent its being + * freed, and we'll pull it off the list in the free path. + */ + struct list_head inactive_list; + + /** LRU list of objects with fence regs on them. */ + struct list_head fence_list; + + /** + * We leave the user IRQ off as much as possible, + * but this means that requests will finish and never + * be retired once the system goes idle. Set a timer to + * fire periodically while the ring is running. When it + * fires, go retire requests. + */ + struct delayed_work retire_work; + + /** + * Are we in a non-interruptible section of code like + * modesetting? + */ + bool interruptible; + + /** + * Flag if the X Server, and thus DRM, is not currently in + * control of the device. + * + * This is set between LeaveVT and EnterVT. It needs to be + * replaced with a semaphore. It also needs to be + * transitioned away from for kernel modesetting. + */ + int suspended; + + /** Bit 6 swizzling required for X tiling */ + uint32_t bit_6_swizzle_x; + /** Bit 6 swizzling required for Y tiling */ + uint32_t bit_6_swizzle_y; + + /* storage for physical objects */ + struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; + + /* accounting, useful for userland debugging */ + size_t object_memory; + u32 object_count; +}; + +struct i915_gpu_error { + /* For hangcheck timer */ +#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ +#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) + struct timer_list hangcheck_timer; + int hangcheck_count; + uint32_t last_acthd[I915_NUM_RINGS]; + uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; + + /* For reset and error_state handling. */ + struct lock lock; + /* Protected by the above dev->gpu_error.lock. */ + struct drm_i915_error_state *first_error; + struct work_struct work; + + unsigned long last_reset; + + /** + * State variable and reset counter controlling the reset flow + * + * Upper bits are for the reset counter. This counter is used by the + * wait_seqno code to race-free noticed that a reset event happened and + * that it needs to restart the entire ioctl (since most likely the + * seqno it waited for won't ever signal anytime soon). + * + * This is important for lock-free wait paths, where no contended lock + * naturally enforces the correct ordering between the bail-out of the + * waiter and the gpu reset work code. + * + * Lowest bit controls the reset state machine: Set means a reset is in + * progress. This state will (presuming we don't have any bugs) decay + * into either unset (successful reset) or the special WEDGED value (hw + * terminally sour). All waiters on the reset_queue will be woken when + * that happens. + */ + atomic_t reset_counter; + + /** + * Special values/flags for reset_counter + * + * Note that the code relies on + * I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG + * being true. + */ +#define I915_RESET_IN_PROGRESS_FLAG 1 +#define I915_WEDGED 0xffffffff + + /** + * Waitqueue to signal when the reset has completed. Used by clients + * that wait for dev_priv->mm.wedged to settle. + */ + wait_queue_head_t reset_queue; + + /* For gpu hang simulation. */ + unsigned int stop_rings; +}; + +enum modeset_restore { + MODESET_ON_LID_OPEN, + MODESET_DONE, + MODESET_SUSPENDED, +}; + typedef struct drm_i915_private { struct drm_device *dev; + struct kmem_cache *slab; const struct intel_device_info *info; @@ -652,6 +887,7 @@ typedef struct drm_i915_private { device_t *gmbus; + /** gmbus_mutex protects against concurrent usage of the single hw gmbus * controller on different i2c buses. */ struct lock gmbus_mutex; @@ -662,9 +898,11 @@ typedef struct drm_i915_private { */ uint32_t gpio_mmio_base; + wait_queue_head_t gmbus_wait_queue; + struct pci_dev *bridge_dev; struct intel_ring_buffer ring[I915_NUM_RINGS]; - uint32_t next_seqno; + uint32_t last_seqno, next_seqno; drm_dma_handle_t *status_page_dmah; struct resource *mch_res; @@ -675,31 +913,24 @@ typedef struct drm_i915_private { /* protects the irq masks */ struct lock irq_lock; + /* To control wakeup latency, e.g. for irq-driven dp aux transfers. */ + struct pm_qos_request pm_qos; + /* DPIO indirect register protection */ - struct spinlock dpio_lock; + struct lock dpio_lock; /** Cached value of IMR to avoid reads in updating the bitfield */ u32 pipestat[2]; u32 irq_mask; u32 gt_irq_mask; - u32 pch_irq_mask; u32 hotplug_supported_mask; struct work_struct hotplug_work; + bool enable_hotplug_processing; int num_pipe; int num_pch_pll; - /* For hangcheck timer */ -#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */ -#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) - struct timer_list hangcheck_timer; - int hangcheck_count; - uint32_t last_acthd[I915_NUM_RINGS]; - uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; - - unsigned int stop_rings; - unsigned long cfb_size; unsigned int cfb_fb; enum plane cfb_plane; @@ -710,7 +941,7 @@ typedef struct drm_i915_private { /* overlay */ struct intel_overlay *overlay; - bool sprite_scaling_enabled; + unsigned int sprite_scaling_enabled; /* LVDS info */ int backlight_level; /* restore backlight to this value */ @@ -728,7 +959,6 @@ typedef struct drm_i915_private { unsigned int fdi_rx_polarity_inverted:1; int lvds_ssc_freq; unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ - unsigned int lvds_val; /* used for checking LVDS channel mode */ struct { int rate; int lanes; @@ -749,11 +979,6 @@ typedef struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; - struct lock error_lock; - /* Protected by dev->error_lock. */ - struct drm_i915_error_state *first_error; - struct work_struct error_work; - struct completion error_completion; struct workqueue_struct *wq; /* Display functions */ @@ -765,117 +990,12 @@ typedef struct drm_i915_private { unsigned long quirks; - /* Register state */ - bool modeset_on_lid; + enum modeset_restore modeset_restore; + struct lock modeset_restore_lock; - struct { - /** Bridge to intel-gtt-ko */ - struct intel_gtt *gtt; - /** Memory allocator for GTT stolen memory */ - struct drm_mm stolen; - /** Memory allocator for GTT */ - struct drm_mm gtt_space; - /** List of all objects in gtt_space. Used to restore gtt - * mappings on resume */ - struct list_head bound_list; - /** - * List of objects which are not bound to the GTT (thus - * are idle and not used by the GPU) but still have - * (presumably uncached) pages still attached. - */ - struct list_head unbound_list; - - /** Usable portion of the GTT for GEM */ - unsigned long gtt_start; - unsigned long gtt_mappable_end; - unsigned long gtt_end; - unsigned long stolen_base; /* limited to low memory (32-bit) */ - - struct io_mapping *gtt_mapping; - phys_addr_t gtt_base_addr; - int gtt_mtrr; - - /** PPGTT used for aliasing the PPGTT with the GTT */ - struct i915_hw_ppgtt *aliasing_ppgtt; - - bool shrinker_no_lock_stealing; - - /** - * List of objects currently involved in rendering. - * - * Includes buffers having the contents of their GPU caches - * flushed, not necessarily primitives. last_rendering_seqno - * represents when the rendering involved will be completed. - * - * A reference is held on the buffer while on this list. - */ - struct list_head active_list; - - /** - * LRU list of objects which are not in the ringbuffer and - * are ready to unbind, but are still in the GTT. - * - * last_rendering_seqno is 0 while an object is in this list. - * - * A reference is not held on the buffer while on this list, - * as merely being GTT-bound shouldn't prevent its being - * freed, and we'll pull it off the list in the free path. - */ - struct list_head inactive_list; - - /** LRU list of objects with fence regs on them. */ - struct list_head fence_list; - - /** - * We leave the user IRQ off as much as possible, - * but this means that requests will finish and never - * be retired once the system goes idle. Set a timer to - * fire periodically while the ring is running. When it - * fires, go retire requests. - */ - struct delayed_work retire_work; - - /** - * Are we in a non-interruptible section of code like - * modesetting? - */ - bool interruptible; - - /** - * Flag if the X Server, and thus DRM, is not currently in - * control of the device. - * - * This is set between LeaveVT and EnterVT. It needs to be - * replaced with a semaphore. It also needs to be - * transitioned away from for kernel modesetting. - */ - int suspended; - - /** - * Flag if the hardware appears to be wedged. - * - * This is set when attempts to idle the device timeout. - * It prevents command submission from occurring and makes - * every pending request fail - */ - atomic_t wedged; - - /** Bit 6 swizzling required for X tiling */ - uint32_t bit_6_swizzle_x; - /** Bit 6 swizzling required for Y tiling */ - uint32_t bit_6_swizzle_y; - - /* storage for physical objects */ - struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; - - /* accounting, useful for userland debugging */ - size_t gtt_total; - size_t mappable_gtt_total; - size_t object_memory; - u32 object_count; - - eventhandler_tag i915_lowmem; - } mm; + struct i915_gtt gtt; + + struct i915_gem_mm mm; /* Kernel Modesetting */ @@ -917,7 +1037,7 @@ typedef struct drm_i915_private { struct drm_mm_node *compressed_fb; struct drm_mm_node *compressed_llb; - unsigned long last_gpu_reset; + struct i915_gpu_error gpu_error; /* list of fbdev register on this device */ struct intel_fbdev *fbdev; @@ -957,11 +1077,7 @@ enum hdmi_force_audio { HDMI_AUDIO_ON, /* force turn on HDMI audio */ }; -enum i915_cache_level { - I915_CACHE_NONE = 0, - I915_CACHE_LLC, - I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */ -}; +#define I915_GTT_RESERVED ((struct drm_mm_node *)0x1) struct drm_i915_gem_object_ops { /* Interface between the GEM object and its backing storage. @@ -988,6 +1104,8 @@ struct drm_i915_gem_object { /** Current space allocated to this object in the GTT, if any. */ struct drm_mm_node *gtt_space; + /** Stolen memory for this object, instead of being backed by shmem. */ + struct drm_mm_node *stolen; struct list_head gtt_list; /** This object's place on the active/inactive lists */ @@ -1109,13 +1227,6 @@ struct drm_i915_gem_object { /** for phy allocated objects */ struct drm_i915_gem_phys_object *phys_obj; - - /** - * Number of crtcs where this object is currently the fb, but - * will be page flipped away on the next vblank. When it - * reaches 0, dev_priv->pending_flip_queue will be woken up. - */ - atomic_t pending_flip; }; #define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base) @@ -1240,6 +1351,8 @@ struct drm_i915_file_private { #define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5) +#define HAS_DDI(dev) (IS_HASWELL(dev)) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 @@ -1259,6 +1372,8 @@ struct drm_i915_file_private { #define GT_FREQUENCY_MULTIPLIER 50 +#include "i915_trace.h" + /** * RC6 is a special power stage which allows the GPU to enter an very * low-voltage mode when idle, using down to 0V while at this stage. This @@ -1280,9 +1395,7 @@ struct drm_i915_file_private { #define INTEL_RC6p_ENABLE (1<<1) #define INTEL_RC6pp_ENABLE (1<<2) -extern int intel_iommu_enabled; extern struct drm_ioctl_desc i915_ioctls[]; -extern struct drm_driver i915_driver_info; extern struct cdev_pager_ops i915_gem_pager_ops; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc __always_unused; @@ -1295,9 +1408,13 @@ extern int i915_panel_use_ssc __read_mostly; extern int i915_vbt_sdvo_panel_type __read_mostly; extern int i915_enable_rc6 __read_mostly; extern int i915_enable_fbc __read_mostly; -extern int i915_enable_hangcheck; +extern bool i915_enable_hangcheck __read_mostly; extern int i915_enable_ppgtt __read_mostly; extern unsigned int i915_preliminary_hw_support __read_mostly; +extern int i915_disable_power_well __read_mostly; + +extern int i915_master_create(struct drm_device *dev, struct drm_master *master); +extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master); /* i915_dma.c */ void i915_update_dri1_breadcrumb(struct drm_device *dev); @@ -1332,6 +1449,7 @@ void i915_hangcheck_elapsed(unsigned long data); void i915_handle_error(struct drm_device *dev, bool wedged); extern void intel_irq_init(struct drm_device *dev); +extern void intel_hpd_init(struct drm_device *dev); extern void intel_gt_init(struct drm_device *dev); extern void intel_gt_reset(struct drm_device *dev); @@ -1400,22 +1518,41 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); -void i915_gem_unload(struct drm_device *dev); +void *i915_gem_object_alloc(struct drm_device *dev); +void i915_gem_object_free(struct drm_i915_gem_object *obj); int i915_gem_init_object(struct drm_gem_object *obj); void i915_gem_object_init(struct drm_i915_gem_object *obj, const struct drm_i915_gem_object_ops *ops); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); void i915_gem_free_object(struct drm_gem_object *obj); + int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj, uint32_t alignment, bool map_and_fenceable, bool nonblocking); void i915_gem_object_unpin(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj); +int i915_gem_object_put_pages(struct drm_i915_gem_object *obj); void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); +int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj); +static inline struct vm_page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n) +{ + return obj->pages[n]; +} +static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) +{ + BUG_ON(obj->pages == NULL); + obj->pages_pin_count++; +} +static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) +{ + BUG_ON(obj->pages_pin_count == 0); + obj->pages_pin_count--; +} + int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_ring_buffer *to); @@ -1438,8 +1575,8 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) return (int32_t)(seq1 - seq2) >= 0; } -extern int i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); - +int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); +int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno); int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); @@ -1465,8 +1602,18 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring); -int __must_check i915_gem_check_wedge(struct drm_i915_private *dev_priv, +int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); +static inline bool i915_reset_in_progress(struct i915_gpu_error *error) +{ + return unlikely(atomic_read(&error->reset_counter) + & I915_RESET_IN_PROGRESS_FLAG); +} + +static inline bool i915_terminally_wedged(struct i915_gpu_error *error) +{ + return atomic_read(&error->reset_counter) == I915_WEDGED; +} void i915_gem_reset(struct drm_device *dev); void i915_gem_clflush_object(struct drm_i915_gem_object *obj); @@ -1508,13 +1655,22 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); void i915_gem_release(struct drm_device *dev, struct drm_file *file); uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode); +i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode); +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced); int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); +#if 0 +struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf); + +struct dma_buf *i915_gem_prime_export(struct drm_device *dev, + struct drm_gem_object *gem_obj, int flags); +#endif + /* i915_gem_context.c */ void i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); @@ -1527,7 +1683,6 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file); /* i915_gem_gtt.c */ -int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev); void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev); void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj, @@ -1541,12 +1696,10 @@ void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level); void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj); void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj); -void i915_gem_init_global_gtt(struct drm_device *dev, - unsigned long start, - unsigned long mappable_end, - unsigned long end); +void i915_gem_init_global_gtt(struct drm_device *dev); +void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start, + unsigned long mappable_end, unsigned long end); int i915_gem_gtt_init(struct drm_device *dev); -void i915_gem_gtt_fini(struct drm_device *dev); static inline void i915_gem_chipset_flush(struct drm_device *dev) { if (INTEL_INFO(dev)->gen < 6) @@ -1564,14 +1717,29 @@ int i915_gem_evict_everything(struct drm_device *dev); /* i915_gem_stolen.c */ int i915_gem_init_stolen(struct drm_device *dev); +int i915_gem_stolen_setup_compression(struct drm_device *dev, int size); +void i915_gem_stolen_cleanup_compression(struct drm_device *dev); void i915_gem_cleanup_stolen(struct drm_device *dev); +struct drm_i915_gem_object * +i915_gem_object_create_stolen(struct drm_device *dev, u32 size); +void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj); /* i915_gem_tiling.c */ +inline static bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) +{ + drm_i915_private_t *dev_priv = obj->base.dev->dev_private; + + return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && + obj->tiling_mode != I915_TILING_NONE; +} + void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); /* i915_gem_debug.c */ +void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len, + const char *where, uint32_t mark); #if WATCH_LISTS int i915_verify_lists(struct drm_device *dev); #else @@ -1588,6 +1756,10 @@ void i915_debugfs_cleanup(struct drm_minor *minor); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); +/* i915_ums.c */ +void i915_save_display_reg(struct drm_device *dev); +void i915_restore_display_reg(struct drm_device *dev); + /* i915_sysfs.c */ void i915_setup_sysfs(struct drm_device *dev_priv); void i915_teardown_sysfs(struct drm_device *dev_priv); @@ -1602,8 +1774,8 @@ static inline bool intel_gmbus_is_port_valid(unsigned port) extern struct device *intel_gmbus_get_adapter( struct drm_i915_private *dev_priv, unsigned port); -extern void intel_gmbus_set_speed(device_t idev, int speed); -extern void intel_gmbus_force_bit(device_t idev, bool force_bit); +extern void intel_gmbus_set_speed(struct device *adapter, int speed); +extern void intel_gmbus_force_bit(struct device *adapter, bool force_bit); static inline bool intel_gmbus_is_forced_bit(struct device *adapter) { struct intel_iic_softc *sc; @@ -1646,6 +1818,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore); +extern void i915_redisable_vga(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); extern void intel_init_pch_refclk(struct drm_device *dev); @@ -1658,17 +1831,6 @@ extern bool i915_semaphore_is_enabled(struct drm_device *dev); int i915_reg_read_ioctl(struct drm_device *dev, void *data, struct drm_file *file); -extern void intel_overlay_print_error_state(struct sbuf *m, - struct intel_overlay_error_state *error); -extern void intel_display_print_error_state(struct sbuf *m, - struct drm_device *dev, struct intel_display_error_state *error); - -static inline void -trace_i915_reg_rw(boolean_t rw, int reg, uint64_t val, int sz) -{ - return; -} - const struct intel_device_info *i915_get_device_id(int device); /* overlay */ @@ -1730,5 +1892,19 @@ __i915_write(64, 64) #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) +/* "Broadcast RGB" property */ +#define INTEL_BROADCAST_RGB_AUTO 0 +#define INTEL_BROADCAST_RGB_FULL 1 +#define INTEL_BROADCAST_RGB_LIMITED 2 + +static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) +{ + if (HAS_PCH_SPLIT(dev)) + return CPU_VGACNTRL; + else if (IS_VALLEYVIEW(dev)) + return VLV_VGACNTRL; + else + return VGACNTRL; +} #endif diff --git a/sys/dev/drm/i915/i915_gem.c b/sys/dev/drm/i915/i915_gem.c index 0904f94e96..e02738d81c 100644 --- a/sys/dev/drm/i915/i915_gem.c +++ b/sys/dev/drm/i915/i915_gem.c @@ -82,10 +82,8 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, struct drm_i915_fence_reg *fence, bool enable); -static uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, - int tiling_mode); -static uint32_t i915_gem_get_gtt_alignment(struct drm_device *dev, - uint32_t size, int tiling_mode); +static long i915_gem_purge(struct drm_i915_private *dev_priv, long target); + static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj); static void i915_gem_object_truncate(struct drm_i915_gem_object *obj); @@ -103,7 +101,6 @@ static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) static int i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj); static bool i915_gem_object_is_inactive(struct drm_i915_gem_object *obj); -static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj); static void i915_gem_reset_fences(struct drm_device *dev); static void i915_gem_lowmem(void *arg); @@ -123,13 +120,13 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, } static int -i915_gem_wait_for_error(struct drm_device *dev) +i915_gem_wait_for_error(struct i915_gpu_error *error) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct completion *x = &dev_priv->error_completion; int ret; - if (!atomic_read(&dev_priv->mm.wedged)) +#define EXIT_COND (!i915_reset_in_progress(error) || \ + i915_terminally_wedged(error)) + if (EXIT_COND) return 0; /* @@ -137,36 +134,30 @@ i915_gem_wait_for_error(struct drm_device *dev) * userspace. If it takes that long something really bad is going on and * we should simply try to bail out and fail as gracefully as possible. */ - ret = wait_for_completion_interruptible_timeout(x, 10*hz); + ret = wait_event_interruptible_timeout(error->reset_queue, + EXIT_COND, + 10*HZ); if (ret == 0) { DRM_ERROR("Timed out waiting for the gpu reset to complete\n"); return -EIO; } else if (ret < 0) { return ret; } +#undef EXIT_COND - if (atomic_read(&dev_priv->mm.wedged)) { - /* GPU is hung, bump the completion count to account for - * the token we just consumed so that we never hit zero and - * end up waiting upon a subsequent completion event that - * will never happen. - */ - lockmgr(&x->wait.lock, LK_EXCLUSIVE); - x->done++; - lockmgr(&x->wait.lock, LK_RELEASE); - } return 0; } int i915_mutex_lock_interruptible(struct drm_device *dev) { + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - ret = i915_gem_wait_for_error(dev); + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); if (ret) return ret; - ret = lockmgr(&dev->dev_struct_lock, LK_EXCLUSIVE|LK_SLEEPFAIL); + ret = lockmgr(&dev->struct_mutex, LK_EXCLUSIVE|LK_SLEEPFAIL); if (ret) return -EINTR; @@ -197,10 +188,10 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data, if (INTEL_INFO(dev)->gen >= 5) return -ENODEV; - lockmgr(&dev->dev_lock, LK_EXCLUSIVE|LK_RETRY|LK_CANRECURSE); - i915_gem_init_global_gtt(dev, args->gtt_start, - args->gtt_end, args->gtt_end); - lockmgr(&dev->dev_lock, LK_RELEASE); + mutex_lock(&dev->struct_mutex); + i915_gem_setup_global_gtt(dev, args->gtt_start, args->gtt_end, + args->gtt_end); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -215,13 +206,13 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, size_t pinned; pinned = 0; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) if (obj->pin_count) pinned += obj->gtt_space->size; - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); - args->aper_size = dev_priv->mm.gtt_total; + args->aper_size = dev_priv->gtt.total; args->aper_available_size = args->aper_size - pinned; return 0; @@ -295,14 +286,6 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, args->size, &args->handle); } -static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) -{ - drm_i915_private_t *dev_priv = obj->base.dev->dev_private; - - return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 && - obj->tiling_mode != I915_TILING_NONE; -} - static inline void vm_page_reference(vm_page_t m) { vm_page_flag_set(m, PG_REFERENCED); @@ -413,9 +396,101 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, out: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); + return ret; +} + +#if 0 +/* This is the fast write path which cannot handle + * page faults in the source data + */ + +static inline int +fast_user_write(struct io_mapping *mapping, + loff_t page_base, int page_offset, + char __user *user_data, + int length) +{ + void __iomem *vaddr_atomic; + void *vaddr; + unsigned long unwritten; + + vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base); + /* We can use the cpu mem copy function because this is X86. */ + vaddr = (void __force*)vaddr_atomic + page_offset; + unwritten = __copy_from_user_inatomic_nocache(vaddr, + user_data, length); + io_mapping_unmap_atomic(vaddr_atomic); + return unwritten; +} + +/** + * This is the fast pwrite path, where we copy the data directly from the + * user into the GTT, uncached. + */ +static int +i915_gem_gtt_pwrite_fast(struct drm_device *dev, + struct drm_i915_gem_object *obj, + struct drm_i915_gem_pwrite *args, + struct drm_file *file) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + ssize_t remain; + loff_t offset, page_base; + char __user *user_data; + int page_offset, page_length, ret; + + ret = i915_gem_object_pin(obj, 0, true, true); + if (ret) + goto out; + + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) + goto out_unpin; + + ret = i915_gem_object_put_fence(obj); + if (ret) + goto out_unpin; + + user_data = (char __user *) (uintptr_t) args->data_ptr; + remain = args->size; + + offset = obj->gtt_offset + args->offset; + + while (remain > 0) { + /* Operation in this page + * + * page_base = page offset within aperture + * page_offset = offset within page + * page_length = bytes to copy for this page + */ + page_base = offset & PAGE_MASK; + page_offset = offset_in_page(offset); + page_length = remain; + if ((page_offset + remain) > PAGE_SIZE) + page_length = PAGE_SIZE - page_offset; + + /* If we get a fault while copying data, then (presumably) our + * source page isn't available. Return the error and we'll + * retry in the slow path. + */ + if (fast_user_write(dev_priv->gtt.mappable, page_base, + page_offset, user_data, page_length)) { + ret = -EFAULT; + goto out_unpin; + } + + remain -= page_length; + user_data += page_length; + offset += page_length; + } + +out_unpin: + i915_gem_object_unpin(obj); +out: return ret; } +#endif static int i915_gem_gtt_write(struct drm_device *dev, struct drm_i915_gem_object *obj, @@ -580,7 +655,7 @@ out_unpin: out: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); unlocked: vm_page_unhold_pages(ma, npages); free_ma: @@ -589,25 +664,17 @@ free_ma: } int -i915_gem_check_wedge(struct drm_i915_private *dev_priv, +i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible) { - if (atomic_read(&dev_priv->mm.wedged)) { - struct completion *x = &dev_priv->error_completion; - bool recovery_complete; - - /* Give the error handler a chance to run. */ - lockmgr(&x->wait.lock, LK_EXCLUSIVE); - recovery_complete = x->done > 0; - lockmgr(&x->wait.lock, LK_RELEASE); - + if (i915_reset_in_progress(error)) { /* Non-interruptible callers can't handle -EAGAIN, hence return * -EIO unconditionally for these. */ if (!interruptible) return -EIO; - /* Recovery complete, but still wedged means reset failure. */ - if (recovery_complete) + /* Recovery complete, but the reset failed ... */ + if (i915_terminally_wedged(error)) return -EIO; return -EAGAIN; @@ -638,13 +705,22 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno) * __wait_seqno - wait until execution of seqno has finished * @ring: the ring expected to report seqno * @seqno: duh! + * @reset_counter: reset sequence associated with the given seqno * @interruptible: do an interruptible wait (normally yes) * @timeout: in - how long to wait (NULL forever); out - how much time remaining * + * Note: It is of utmost importance that the passed in seqno and reset_counter + * values have been read by the caller in an smp safe manner. Where read-side + * locks are involved, it is sufficient to read the reset_counter before + * unlocking the lock that protects the seqno. For lockless tricks, the + * reset_counter _must_ be read before, and an appropriate smp_rmb must be + * inserted. + * * Returns 0 if the seqno was found within the alloted time. Else returns the * errno with remaining time filled in timeout argument. */ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, + unsigned reset_counter, bool interruptible, struct timespec *timeout) { drm_i915_private_t *dev_priv = ring->dev->dev_private; @@ -672,7 +748,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, #define EXIT_COND \ (i915_seqno_passed(ring->get_seqno(ring, false), seqno) || \ - atomic_read(&dev_priv->mm.wedged)) + i915_reset_in_progress(&dev_priv->gpu_error) || \ + reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) do { if (interruptible) end = wait_event_interruptible_timeout(ring->irq_queue, @@ -682,7 +759,14 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, end = wait_event_timeout(ring->irq_queue, EXIT_COND, timeout_jiffies); - ret = i915_gem_check_wedge(dev_priv, interruptible); + /* We need to check whether any gpu reset happened in between + * the caller grabbing the seqno and now ... */ + if (reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) + end = -EAGAIN; + + /* ... but upgrade the -EGAIN to an -EIO if the gpu is truely + * gone. */ + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) end = ret; } while (end == 0 && wait_forever); @@ -727,7 +811,7 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) DRM_LOCK_ASSERT(dev); BUG_ON(seqno == 0); - ret = i915_gem_check_wedge(dev_priv, interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible); if (ret) return ret; @@ -735,7 +819,9 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno) if (ret) return ret; - return __wait_seqno(ring, seqno, interruptible, NULL); + return __wait_seqno(ring, seqno, + atomic_read(&dev_priv->gpu_error.reset_counter), + interruptible, NULL); } /** @@ -782,6 +868,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring = obj->ring; + unsigned reset_counter; u32 seqno; int ret; @@ -792,7 +879,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (seqno == 0) return 0; - ret = i915_gem_check_wedge(dev_priv, true); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, true); if (ret) return ret; @@ -800,9 +887,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (ret) return ret; - DRM_UNLOCK(dev); - ret = __wait_seqno(ring, seqno, true, NULL); - DRM_LOCK(dev); + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + mutex_unlock(&dev->struct_mutex); + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); + mutex_lock(&dev->struct_mutex); i915_gem_retire_requests_ring(ring); @@ -879,7 +967,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, unref: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -909,7 +997,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -984,6 +1072,93 @@ out: * suffer if the GTT working set is large or there are few fence registers * left. */ +#if 0 +int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data); + struct drm_device *dev = obj->base.dev; + drm_i915_private_t *dev_priv = dev->dev_private; + pgoff_t page_offset; + unsigned long pfn; + int ret = 0; + bool write = !!(vmf->flags & FAULT_FLAG_WRITE); + + /* We don't use vmf->pgoff since that has the fake offset */ + page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> + PAGE_SHIFT; + + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto out; + + trace_i915_gem_object_fault(obj, page_offset, true, write); + + /* Access to snoopable pages through the GTT is incoherent. */ + if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev)) { + ret = -EINVAL; + goto unlock; + } + + /* Now bind it into the GTT if needed */ + ret = i915_gem_object_pin(obj, 0, true, false); + if (ret) + goto unlock; + + ret = i915_gem_object_set_to_gtt_domain(obj, write); + if (ret) + goto unpin; + + ret = i915_gem_object_get_fence(obj); + if (ret) + goto unpin; + + obj->fault_mappable = true; + + pfn = ((dev_priv->gtt.mappable_base + obj->gtt_offset) >> PAGE_SHIFT) + + page_offset; + + /* Finally, remap it using the new GTT offset */ + ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); +unpin: + i915_gem_object_unpin(obj); +unlock: + mutex_unlock(&dev->struct_mutex); +out: + switch (ret) { + case -EIO: + /* If this -EIO is due to a gpu hang, give the reset code a + * chance to clean up the mess. Otherwise return the proper + * SIGBUS. */ + if (i915_terminally_wedged(&dev_priv->gpu_error)) + return VM_FAULT_SIGBUS; + case -EAGAIN: + /* Give the error handler a chance to run and move the + * objects off the GPU active list. Next time we service the + * fault, we should be able to transition the page into the + * GTT without touching the GPU (and so avoid further + * EIO/EGAIN). If the GPU is wedged, then there is no issue + * with coherency, just lost writes. + */ + set_need_resched(); + case 0: + case -ERESTARTSYS: + case -EINTR: + case -EBUSY: + /* + * EBUSY is ok: this just means that another thread + * already did the job. + */ + return VM_FAULT_NOPAGE; + case -ENOMEM: + return VM_FAULT_OOM; + case -ENOSPC: + return VM_FAULT_SIGBUS; + default: + WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret); + return VM_FAULT_SIGBUS; + } +} +#endif /** * i915_gem_release_mmap - remove physical page mappings @@ -1027,7 +1202,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) obj->fault_mappable = false; } -static uint32_t +uint32_t i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) { uint32_t gtt_size; @@ -1055,17 +1230,16 @@ i915_gem_get_gtt_size(struct drm_device *dev, uint32_t size, int tiling_mode) * Return the required GTT alignment for an object, taking into account * potential fence register mapping. */ -static uint32_t -i915_gem_get_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode) +uint32_t +i915_gem_get_gtt_alignment(struct drm_device *dev, uint32_t size, + int tiling_mode, bool fenced) { /* * Minimum alignment is 4k (GTT page size), but might be greater * if a fence register is needed for the object. */ - if (INTEL_INFO(dev)->gen >= 4 || + if (INTEL_INFO(dev)->gen >= 4 || (!fenced && IS_G33(dev)) || tiling_mode == I915_TILING_NONE) return 4096; @@ -1076,35 +1250,6 @@ i915_gem_get_gtt_alignment(struct drm_device *dev, return i915_gem_get_gtt_size(dev, size, tiling_mode); } -/** - * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an - * unfenced object - * @dev: the device - * @size: size of the object - * @tiling_mode: tiling mode of the object - * - * Return the required GTT alignment for an object, only taking into account - * unfenced tiled surface requirements. - */ -uint32_t -i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev, - uint32_t size, - int tiling_mode) -{ - /* - * Minimum alignment is 4k (GTT page size) for sane hw. - */ - if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) || - tiling_mode == I915_TILING_NONE) - return 4096; - - /* Previous hardware however needs to be aligned to a power-of-two - * tile height. The simplest method for determining this is to reuse - * the power-of-tile object size. - */ - return i915_gem_get_gtt_size(dev, size, tiling_mode); -} - int i915_gem_mmap_gtt(struct drm_file *file, struct drm_device *dev, @@ -1125,7 +1270,7 @@ i915_gem_mmap_gtt(struct drm_file *file, goto unlock; } - if (obj->base.size > dev_priv->mm.gtt_mappable_end) { + if (obj->base.size > dev_priv->gtt.mappable_end) { ret = -E2BIG; goto out; } @@ -1145,7 +1290,7 @@ i915_gem_mmap_gtt(struct drm_file *file, out: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -1225,9 +1370,37 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj) obj->pages = NULL; } +int +i915_gem_object_put_pages(struct drm_i915_gem_object *obj) +{ + const struct drm_i915_gem_object_ops *ops = obj->ops; + + if (obj->pages == NULL) + return 0; + + BUG_ON(obj->gtt_space); + + if (obj->pages_pin_count) + return -EBUSY; + + /* ->put_pages might need to allocate memory for the bit17 swizzle + * array, hence protect them from being reaped by removing them from gtt + * lists early. */ + list_del(&obj->gtt_list); + + ops->put_pages(obj); + obj->pages = NULL; + + if (i915_gem_object_is_purgeable(obj)) + i915_gem_object_truncate(obj); + + return 0; +} + static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct drm_device *dev; vm_object_t vm_obj; int page_count, i, j; @@ -1244,8 +1417,10 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) for (i = 0; i < page_count; i++) { page = shmem_read_mapping_page(vm_obj, i); - if (IS_ERR(page)) + if (IS_ERR(page)) { + i915_gem_purge(dev_priv, page_count); goto err_pages; + } obj->pages[i] = page; } @@ -1269,6 +1444,38 @@ err_pages: return (-EIO); } +/* Ensure that the associated pages are gathered from the backing storage + * and pinned into our object. i915_gem_object_get_pages() may be called + * multiple times before they are released by a single call to + * i915_gem_object_put_pages() - once the pages are no longer referenced + * either as a result of memory pressure (reaping pages under the shrinker) + * or as the object is itself released. + */ +int +i915_gem_object_get_pages(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + const struct drm_i915_gem_object_ops *ops = obj->ops; + int ret; + + if (obj->pages) + return 0; + + if (obj->madv != I915_MADV_WILLNEED) { + DRM_ERROR("Attempting to obtain a purgeable object\n"); + return -EINVAL; + } + + BUG_ON(obj->pages_pin_count); + + ret = ops->get_pages(obj); + if (ret) + return ret; + + list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list); + return 0; +} + void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring) @@ -1334,30 +1541,24 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj) } static int -i915_gem_handle_seqno_wrap(struct drm_device *dev) +i915_gem_init_seqno(struct drm_device *dev, u32 seqno) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; int ret, i, j; - /* The hardware uses various monotonic 32-bit counters, if we - * detect that they will wraparound we need to idle the GPU - * and reset those counters. - */ - ret = 0; + /* Carefully retire all requests without writing to the rings */ for_each_ring(ring, dev_priv, i) { - for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) - ret |= ring->sync_seqno[j] != 0; + ret = intel_ring_idle(ring); + if (ret) + return ret; } - if (ret == 0) - return ret; - - ret = i915_gpu_idle(dev); - if (ret) - return ret; - i915_gem_retire_requests(dev); + + /* Finally reset hw state */ for_each_ring(ring, dev_priv, i) { + intel_ring_init_seqno(ring, seqno); + for (j = 0; j < ARRAY_SIZE(ring->sync_seqno); j++) ring->sync_seqno[j] = 0; } @@ -1365,6 +1566,32 @@ i915_gem_handle_seqno_wrap(struct drm_device *dev) return 0; } +int i915_gem_set_seqno(struct drm_device *dev, u32 seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + + if (seqno == 0) + return -EINVAL; + + /* HWS page needs to be set less than what we + * will inject to ring + */ + ret = i915_gem_init_seqno(dev, seqno - 1); + if (ret) + return ret; + + /* Carefully set the last_seqno value so that wrap + * detection still works + */ + dev_priv->next_seqno = seqno; + dev_priv->last_seqno = seqno - 1; + if (dev_priv->last_seqno == 0) + dev_priv->last_seqno--; + + return 0; +} + int i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) { @@ -1372,14 +1599,14 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) /* reserve 0 for non-seqno */ if (dev_priv->next_seqno == 0) { - int ret = i915_gem_handle_seqno_wrap(dev); + int ret = i915_gem_init_seqno(dev, 0); if (ret) return ret; dev_priv->next_seqno = 1; } - *seqno = dev_priv->next_seqno++; + *seqno = dev_priv->last_seqno = dev_priv->next_seqno++; return 0; } @@ -1445,7 +1672,7 @@ i915_add_request(struct intel_ring_buffer *ring, if (!dev_priv->mm.suspended) { if (i915_enable_hangcheck) { - mod_timer(&dev_priv->hangcheck_timer, + mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } if (was_empty) { @@ -1620,6 +1847,49 @@ i915_gem_retire_requests(struct drm_device *dev) i915_gem_retire_requests_ring(ring); } +static long +__i915_gem_shrink(struct drm_i915_private *dev_priv, long target, + bool purgeable_only) +{ + struct drm_i915_gem_object *obj, *next; + long count = 0; + + list_for_each_entry_safe(obj, next, + &dev_priv->mm.unbound_list, + gtt_list) { +#if 0 + if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && + i915_gem_object_put_pages(obj) == 0) { + count += obj->base.size >> PAGE_SHIFT; + if (count >= target) + return count; + } +#endif + } + + list_for_each_entry_safe(obj, next, + &dev_priv->mm.inactive_list, + mm_list) { +#if 0 + if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) && + i915_gem_object_unbind(obj) == 0 && + i915_gem_object_put_pages(obj) == 0) { + count += obj->base.size >> PAGE_SHIFT; + if (count >= target) + return count; + } +#endif + } + + return count; +} + +static long +i915_gem_purge(struct drm_i915_private *dev_priv, long target) +{ + return __i915_gem_shrink(dev_priv, target, true); +} + static void i915_gem_retire_work_handler(struct work_struct *work) { @@ -1634,7 +1904,7 @@ i915_gem_retire_work_handler(struct work_struct *work) dev = dev_priv->dev; /* Come back later if the device is busy... */ - if (lockmgr(&dev->dev_struct_lock, LK_EXCLUSIVE|LK_NOWAIT)) { + if (lockmgr(&dev->struct_mutex, LK_EXCLUSIVE|LK_NOWAIT)) { queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, round_jiffies_up_relative(hz)); return; @@ -1659,7 +1929,7 @@ i915_gem_retire_work_handler(struct work_struct *work) if (idle) intel_mark_idle(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } /** * Ensures that an object will eventually get non-busy by flushing any required @@ -1707,10 +1977,12 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) int i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_wait *args = data; struct drm_i915_gem_object *obj; struct intel_ring_buffer *ring = NULL; struct timespec timeout_stack, *timeout = NULL; + unsigned reset_counter; u32 seqno = 0; int ret = 0; @@ -1725,7 +1997,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->bo_handle)); if (&obj->base == NULL) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return -ENOENT; } @@ -1751,9 +2023,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) } drm_gem_object_unreference(&obj->base); - DRM_UNLOCK(dev); + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + mutex_unlock(&dev->struct_mutex); - ret = __wait_seqno(ring, seqno, true, timeout); + ret = __wait_seqno(ring, seqno, reset_counter, true, timeout); if (timeout) { WARN_ON(!timespec_valid(timeout)); args->timeout_ns = timespec_to_ns(timeout); @@ -1762,7 +2035,7 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) out: drm_gem_object_unreference(&obj->base); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -1817,15 +2090,15 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj) { u32 old_write_domain, old_read_domains; - /* Act a barrier for all accesses through the GTT */ - cpu_mfence(); - /* Force a pagefault for domain tracking on next user access */ i915_gem_release_mmap(obj); if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) return; + /* Wait for any direct GTT access to complete */ + cpu_mfence(); + old_read_domains = obj->base.read_domains; old_write_domain = obj->base.write_domain; @@ -1841,7 +2114,7 @@ int i915_gem_object_unbind(struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = obj->base.dev->dev_private; - int ret = 0; + int ret; if (obj->gtt_space == NULL) return 0; @@ -1927,52 +2200,38 @@ int i915_gpu_idle(struct drm_device *dev) return 0; } -static void sandybridge_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - uint64_t val; - - if (obj) { - u32 size = obj->gtt_space->size; - - val = (uint64_t)((obj->gtt_offset + size - 4096) & - 0xfffff000) << 32; - val |= obj->gtt_offset & 0xfffff000; - val |= (uint64_t)((obj->stride / 128) - 1) << - SANDYBRIDGE_FENCE_PITCH_SHIFT; - - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; - } else - val = 0; - - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val); - POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8); -} - static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { drm_i915_private_t *dev_priv = dev->dev_private; + int fence_reg; + int fence_pitch_shift; uint64_t val; + if (INTEL_INFO(dev)->gen >= 6) { + fence_reg = FENCE_REG_SANDYBRIDGE_0; + fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + } else { + fence_reg = FENCE_REG_965_0; + fence_pitch_shift = I965_FENCE_PITCH_SHIFT; + } + if (obj) { u32 size = obj->gtt_space->size; val = (uint64_t)((obj->gtt_offset + size - 4096) & 0xfffff000) << 32; val |= obj->gtt_offset & 0xfffff000; - val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT; + val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; if (obj->tiling_mode == I915_TILING_Y) val |= 1 << I965_FENCE_TILING_Y_SHIFT; val |= I965_FENCE_REG_VALID; } else val = 0; - I915_WRITE64(FENCE_REG_965_0 + reg * 8, val); - POSTING_READ(FENCE_REG_965_0 + reg * 8); + fence_reg += reg * 8; + I915_WRITE64(fence_reg, val); + POSTING_READ(fence_reg); } static void i915_write_fence_reg(struct drm_device *dev, int reg, @@ -2051,18 +2310,37 @@ static void i830_write_fence_reg(struct drm_device *dev, int reg, POSTING_READ(FENCE_REG_830_0 + reg * 4); } +inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) +{ + return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; +} + static void i915_gem_write_fence(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) + cpu_mfence(); + switch (INTEL_INFO(dev)->gen) { case 7: - case 6: sandybridge_write_fence_reg(dev, reg, obj); break; + case 6: case 5: case 4: i965_write_fence_reg(dev, reg, obj); break; case 3: i915_write_fence_reg(dev, reg, obj); break; case 2: i830_write_fence_reg(dev, reg, obj); break; - default: break; + default: BUG(); } + + /* And similarly be paranoid that no direct access to this region + * is reordered to before the fence is installed. + */ + if (i915_gem_object_needs_mb(obj)) + cpu_mfence(); } static inline int fence_number(struct drm_i915_private *dev_priv, @@ -2105,7 +2383,7 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, } static int -i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) +i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) { if (obj->last_fenced_seqno) { int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno); @@ -2115,12 +2393,6 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj) obj->last_fenced_seqno = 0; } - /* Ensure that all CPU reads are completed before installing a fence - * and all writes before removing the fence. - */ - if (obj->base.read_domains & I915_GEM_DOMAIN_GTT) - cpu_mfence(); - obj->fenced_gpu_access = false; return 0; } @@ -2131,7 +2403,7 @@ i915_gem_object_put_fence(struct drm_i915_gem_object *obj) struct drm_i915_private *dev_priv = obj->base.dev->dev_private; int ret; - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_wait_fence(obj); if (ret) return ret; @@ -2205,7 +2477,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) * will need to serialise the write to the associated fence register? */ if (obj->fence_dirty) { - ret = i915_gem_object_flush_fence(obj); + ret = i915_gem_object_wait_fence(obj); if (ret) return ret; } @@ -2226,7 +2498,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) if (reg->obj) { struct drm_i915_gem_object *old = reg->obj; - ret = i915_gem_object_flush_fence(old); + ret = i915_gem_object_wait_fence(old); if (ret) return ret; @@ -2249,7 +2521,7 @@ static bool i915_gem_valid_gtt_space(struct drm_device *dev, /* On non-LLC machines we have to be careful when putting differing * types of snoopable memory together to avoid the prefetcher - * crossing memory domains and dieing. + * crossing memory domains and dying. */ if (HAS_LLC(dev)) return true; @@ -2327,21 +2599,21 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, bool mappable, fenceable; int ret; - if (obj->madv != I915_MADV_WILLNEED) { - DRM_ERROR("Attempting to bind a purgeable object\n"); - return -EINVAL; - } + fence_size = i915_gem_get_gtt_size(dev, + obj->base.size, + obj->tiling_mode); + fence_alignment = i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode, true); + unfenced_alignment = + i915_gem_get_gtt_alignment(dev, + obj->base.size, + obj->tiling_mode, false); - fence_size = i915_gem_get_gtt_size(dev, obj->base.size, - obj->tiling_mode); - fence_alignment = i915_gem_get_gtt_alignment(dev, obj->base.size, - obj->tiling_mode); - unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(dev, - obj->base.size, obj->tiling_mode); if (alignment == 0) alignment = map_and_fenceable ? fence_alignment : - unfenced_alignment; - if (map_and_fenceable && (alignment & (fence_alignment - 1)) != 0) { + unfenced_alignment; + if (map_and_fenceable && alignment & (fence_alignment - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); return -EINVAL; } @@ -2351,10 +2623,9 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, /* If the object is bigger than the entire aperture, reject it early * before evicting everything in a vain attempt to find space. */ - if (obj->base.size > (map_and_fenceable ? - dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) { - DRM_ERROR( -"Attempting to bind an object larger than the aperture\n"); + if (obj->base.size > + (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) { + DRM_ERROR("Attempting to bind an object larger than the aperture\n"); return -E2BIG; } @@ -2363,19 +2634,18 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, free_space = drm_mm_search_free_in_range_color(&dev_priv->mm.gtt_space, size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end, + 0, dev_priv->gtt.mappable_end, false); else free_space = drm_mm_search_free_color(&dev_priv->mm.gtt_space, size, alignment, obj->cache_level, false); - if (free_space != NULL) { if (map_and_fenceable) obj->gtt_space = drm_mm_get_block_range_generic(free_space, size, alignment, obj->cache_level, - 0, dev_priv->mm.gtt_mappable_end, + 0, dev_priv->gtt.mappable_end, false); else obj->gtt_space = @@ -2425,7 +2695,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj, (obj->gtt_space->start & (fence_alignment - 1)) == 0; mappable = - obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end; + obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end; + obj->map_and_fenceable = mappable && fenceable; i915_gem_verify_gtt(dev); @@ -2443,6 +2714,13 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj) if (obj->pages == NULL) return; + /* + * Stolen memory is always coherent with the GPU as it is explicitly + * marked as wc by the system, or the system is cache-coherent. + */ + if (obj->stolen) + return; + /* If the GPU is snooping the contents of the CPU cache, * we do not need to manually clear the CPU cache lines. However, * the caches are only snooped when the render cache is @@ -2521,6 +2799,13 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) i915_gem_object_flush_cpu_write_domain(obj); + /* Serialise direct access to this object with the barriers for + * coherent writes from the GPU, by effectively invalidating the + * GTT domain upon first access. + */ + if ((obj->base.read_domains & I915_GEM_DOMAIN_GTT) == 0) + cpu_mfence(); + old_write_domain = obj->base.write_domain; old_read_domains = obj->base.read_domains; @@ -2635,7 +2920,7 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -2672,7 +2957,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -2812,11 +3097,17 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) unsigned long recent_enough = jiffies - msecs_to_jiffies(20); struct drm_i915_gem_request *request; struct intel_ring_buffer *ring = NULL; + unsigned reset_counter; u32 seqno = 0; int ret; - if (atomic_read(&dev_priv->mm.wedged)) - return -EIO; + ret = i915_gem_wait_for_error(&dev_priv->gpu_error); + if (ret) + return ret; + + ret = i915_gem_check_wedge(&dev_priv->gpu_error, false); + if (ret) + return ret; spin_lock(&file_priv->mm.lock); list_for_each_entry(request, &file_priv->mm.request_list, client_list) { @@ -2826,13 +3117,13 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) ring = request->ring; seqno = request->seqno; } + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); spin_unlock(&file_priv->mm.lock); if (seqno == 0) return 0; - ret = __wait_seqno(ring, seqno, true, NULL); - + ret = __wait_seqno(ring, seqno, reset_counter, true, NULL); if (ret == 0) queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0); @@ -2946,7 +3237,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data, out: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -2983,7 +3274,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data, out: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -3019,7 +3310,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -3073,7 +3364,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, out: drm_gem_object_unreference(&obj->base); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -3198,16 +3489,16 @@ i915_gem_idle(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int ret; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); if (dev_priv->mm.suspended) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return 0; } ret = i915_gpu_idle(dev); if (ret) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } i915_gem_retire_requests(dev); @@ -3223,12 +3514,12 @@ i915_gem_idle(struct drm_device *dev) * And not confound mm.suspended! */ dev_priv->mm.suspended = 1; - del_timer_sync(&dev_priv->hangcheck_timer); + del_timer_sync(&dev_priv->gpu_error.hangcheck_timer); i915_kernel_lost_context(dev); i915_gem_cleanup_ringbuffer(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); /* Cancel the retire work handler, which should be idle now. */ cancel_delayed_work_sync(&dev_priv->mm.retire_work); @@ -3285,8 +3576,10 @@ void i915_gem_init_swizzling(struct drm_device *dev) I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL); if (IS_GEN6(dev)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB)); - else + else if (IS_GEN7(dev)) I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB)); + else + BUG(); } static bool @@ -3308,19 +3601,11 @@ intel_enable_blt(struct drm_device *dev) return true; } -int -i915_gem_init_hw(struct drm_device *dev) +static int i915_gem_init_rings(struct drm_device *dev) { - drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; - if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) - I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); - - i915_gem_l3_remap(dev); - - i915_gem_init_swizzling(dev); - ret = intel_init_render_ring_buffer(dev); if (ret) return ret; @@ -3337,76 +3622,63 @@ i915_gem_init_hw(struct drm_device *dev) goto cleanup_bsd_ring; } - dev_priv->next_seqno = 1; - - /* - * XXX: There was some w/a described somewhere suggesting loading - * contexts before PPGTT. - */ - i915_gem_context_init(dev); - i915_gem_init_ppgtt(dev); + ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000)); + if (ret) + goto cleanup_blt_ring; return 0; +cleanup_blt_ring: + intel_cleanup_ring_buffer(&dev_priv->ring[BCS]); cleanup_bsd_ring: intel_cleanup_ring_buffer(&dev_priv->ring[VCS]); cleanup_render_ring: intel_cleanup_ring_buffer(&dev_priv->ring[RCS]); + return ret; } -static bool -intel_enable_ppgtt(struct drm_device *dev) +int +i915_gem_init_hw(struct drm_device *dev) { - if (i915_enable_ppgtt >= 0) - return i915_enable_ppgtt; + drm_i915_private_t *dev_priv = dev->dev_private; + int ret; - /* Disable ppgtt on SNB if VT-d is on. */ - if (INTEL_INFO(dev)->gen == 6 && intel_iommu_enabled) - return false; +#if 0 + if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) + return -EIO; +#endif - return true; + if (IS_HASWELL(dev) && (I915_READ(0x120010) == 1)) + I915_WRITE(0x9008, I915_READ(0x9008) | 0xf0000); + + i915_gem_l3_remap(dev); + + i915_gem_init_swizzling(dev); + + ret = i915_gem_init_rings(dev); + if (ret) + return ret; + + /* + * XXX: There was some w/a described somewhere suggesting loading + * contexts before PPGTT. + */ + i915_gem_context_init(dev); + i915_gem_init_ppgtt(dev); + + return 0; } int i915_gem_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long gtt_size, mappable_size; int ret; - gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; - mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; - - DRM_LOCK(dev); - if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { - /* PPGTT pdes are stolen from global gtt ptes, so shrink the - * aperture accordingly when using aliasing ppgtt. */ - gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; - - i915_gem_init_global_gtt(dev, 0, mappable_size, gtt_size); - - ret = i915_gem_init_aliasing_ppgtt(dev); - if (ret) { - DRM_UNLOCK(dev); - return ret; - } - } else { - /* Let GEM Manage all of the aperture. - * - * However, leave one page at the end still bound to the scratch - * page. There are a number of places where the hardware - * apparently prefetches past the end of the object, and we've - * seen multiple hangs with the GPU head pointer stuck in a - * batchbuffer bound at the last page of the aperture. One page - * should be enough to keep any prefetching inside of the - * aperture. - */ - i915_gem_init_global_gtt(dev, 0, mappable_size, - gtt_size); - } - + mutex_lock(&dev->struct_mutex); + i915_gem_init_global_gtt(dev); ret = i915_gem_init_hw(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); if (ret) { i915_gem_cleanup_aliasing_ppgtt(dev); return ret; @@ -3439,22 +3711,22 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - if (atomic_read(&dev_priv->mm.wedged)) { + if (i915_reset_in_progress(&dev_priv->gpu_error)) { DRM_ERROR("Reenabling wedged hardware, good luck\n"); - atomic_set(&dev_priv->mm.wedged, 0); + atomic_set(&dev_priv->gpu_error.reset_counter, 0); } - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); dev_priv->mm.suspended = 0; ret = i915_gem_init_hw(dev); if (ret != 0) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } KASSERT(list_empty(&dev_priv->mm.active_list), ("active list")); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); ret = drm_irq_install(dev); if (ret) @@ -3463,10 +3735,10 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, return 0; cleanup_ringbuffer: - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); i915_gem_cleanup_ringbuffer(dev); dev_priv->mm.suspended = 1; - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -3519,7 +3791,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); - init_completion(&dev_priv->error_completion); + init_waitqueue_head(&dev_priv->gpu_error.reset_queue); /* On GEN3 we really need to make sure the ARB C3 LP bit is set */ if (IS_GEN3(dev)) { @@ -3551,7 +3823,7 @@ i915_gem_load(struct drm_device *dev) dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS; register_shrinker(&dev_priv->mm.inactive_shrinker); #else - dev_priv->mm.i915_lowmem = EVENTHANDLER_REGISTER(vm_lowmem, + dev_priv->mm.inactive_shrinker = EVENTHANDLER_REGISTER(vm_lowmem, i915_gem_lowmem, dev, EVENTHANDLER_PRI_ANY); #endif } @@ -3748,9 +4020,9 @@ i915_gem_phys_pwrite(struct drm_device *dev, * of the obj, so we can safely drop the lock and continue * to access vaddr. */ - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); unwritten = copy_from_user(vaddr, user_data, args->size); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); if (unwritten) return -EFAULT; } @@ -3844,7 +4116,7 @@ unlocked_vmobj: goto out; } } else - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); /* * Since the object lock was dropped, other thread might have @@ -3855,7 +4127,7 @@ unlocked_vmobj: m = vm_page_lookup(vm_obj, OFF_TO_IDX(offset)); if (m != NULL) { if ((m->flags & PG_BUSY) != 0) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); #if 0 /* XXX */ vm_page_sleep(m, "915pee"); #endif @@ -3865,6 +4137,12 @@ unlocked_vmobj: } else VM_OBJECT_UNLOCK(vm_obj); + /* Access to snoopable pages through the GTT is incoherent. */ + if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev)) { + ret = -EINVAL; + goto unlock; + } + /* Now bind it into the GTT if needed */ if (!obj->map_and_fenceable) { ret = i915_gem_object_unbind(obj); @@ -3913,7 +4191,7 @@ unlocked_vmobj: KASSERT(m->wire_count == 1, ("wire_count not 1 %p", m)); if ((m->flags & PG_BUSY) != 0) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); #if 0 /* XXX */ vm_page_sleep(m, "915pbs"); #endif @@ -3925,7 +4203,7 @@ have_page: *mres = m; vm_page_busy_try(m, false); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); if (oldm != NULL) { vm_page_free(oldm); } @@ -3933,7 +4211,7 @@ have_page: return (VM_PAGER_OK); unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); out: KASSERT(ret != 0, ("i915_gem_pager_fault: wrong return")); if (ret == -EAGAIN || ret == -EIO || ret == -EINTR) { @@ -3953,11 +4231,11 @@ i915_gem_pager_dtor(void *handle) obj = handle; dev = obj->dev; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); drm_gem_free_mmap_offset(obj); i915_gem_release_mmap(to_intel_bo(obj)); drm_gem_object_unreference(obj); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } struct cdev_pager_ops i915_gem_pager_ops = { @@ -4012,7 +4290,7 @@ i915_gem_lowmem(void *arg) dev = arg; dev_priv = dev->dev_private; - if (lockmgr(&dev->dev_struct_lock, LK_EXCLUSIVE|LK_NOWAIT)) + if (lockmgr(&dev->struct_mutex, LK_EXCLUSIVE|LK_NOWAIT)) return; rescan: @@ -4049,14 +4327,5 @@ rescan: if (i915_gpu_idle(dev) == 0) goto rescan; } - DRM_UNLOCK(dev); -} - -void -i915_gem_unload(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv; - - dev_priv = dev->dev_private; - EVENTHANDLER_DEREGISTER(vm_lowmem, dev_priv->mm.i915_lowmem); + mutex_unlock(&dev->struct_mutex); } diff --git a/sys/dev/drm/i915/i915_gem_context.c b/sys/dev/drm/i915/i915_gem_context.c index d12744142b..237af0446a 100644 --- a/sys/dev/drm/i915/i915_gem_context.c +++ b/sys/dev/drm/i915/i915_gem_context.c @@ -127,13 +127,8 @@ static int get_context_size(struct drm_device *dev) static void do_destroy(struct i915_hw_context *ctx) { - struct drm_device *dev = ctx->obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - if (ctx->file_priv) idr_remove(&ctx->file_priv->context_idr, ctx->id); - else - BUG_ON(ctx != dev_priv->ring[RCS].default_context); drm_gem_object_unreference(&ctx->obj->base); kfree(ctx, M_DRM); @@ -250,7 +245,6 @@ err_destroy: void i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ctx_size; if (!HAS_HW_CONTEXTS(dev)) { dev_priv->hw_contexts_disabled = true; @@ -262,11 +256,9 @@ void i915_gem_context_init(struct drm_device *dev) dev_priv->ring[RCS].default_context) return; - ctx_size = get_context_size(dev); - dev_priv->hw_context_size = get_context_size(dev); - dev_priv->hw_context_size = round_up(dev_priv->hw_context_size, 4096); + dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); - if (ctx_size <= 0 || ctx_size > (1<<20)) { + if (dev_priv->hw_context_size > (1<<20)) { dev_priv->hw_contexts_disabled = true; return; } @@ -311,10 +303,10 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); idr_destroy(&file_priv->context_idr); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } static struct i915_hw_context * @@ -501,7 +493,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, return ret; ctx = create_hw_context(dev, file_priv); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -528,13 +520,13 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data, ctx = i915_gem_context_get(file_priv, args->ctx_id); if (!ctx) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return -ENOENT; } do_destroy(ctx); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id); return 0; diff --git a/sys/dev/drm/i915/i915_gem_evict.c b/sys/dev/drm/i915/i915_gem_evict.c index 0ba51e6c6a..c86d5d9356 100644 --- a/sys/dev/drm/i915/i915_gem_evict.c +++ b/sys/dev/drm/i915/i915_gem_evict.c @@ -27,8 +27,9 @@ */ #include -#include #include "i915_drv.h" +#include +#include "i915_trace.h" static bool mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind) @@ -50,6 +51,8 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, struct drm_i915_gem_object *obj; int ret = 0; + trace_i915_gem_evict(dev, min_size, alignment, mappable); + /* * The goal is to evict objects and amalgamate space in LRU order. * The oldest idle objects reside on the inactive list, which is in @@ -77,7 +80,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size, if (mappable) drm_mm_init_scan_with_range(&dev_priv->mm.gtt_space, min_size, alignment, cache_level, - 0, dev_priv->mm.gtt_mappable_end); + 0, dev_priv->gtt.mappable_end); else drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment, cache_level); @@ -160,6 +163,8 @@ i915_gem_evict_everything(struct drm_device *dev) if (lists_empty) return -ENOSPC; + trace_i915_gem_evict_everything(dev); + /* The gpu_idle will flush everything in the write domain to the * active list. Then we must move everything off the active list * with retire requests. diff --git a/sys/dev/drm/i915/i915_gem_execbuffer.c b/sys/dev/drm/i915/i915_gem_execbuffer.c index d52208a211..357e7edd69 100644 --- a/sys/dev/drm/i915/i915_gem_execbuffer.c +++ b/sys/dev/drm/i915/i915_gem_execbuffer.c @@ -28,65 +28,139 @@ #include #include -#include #include "i915_drv.h" +#include "i915_trace.h" #include "intel_drv.h" +#include struct eb_objects { + struct list_head objects; int and; - struct hlist_head buckets[0]; + union { + struct drm_i915_gem_object *lut[0]; + struct hlist_head buckets[0]; + }; }; static struct eb_objects * -eb_create(int size) +eb_create(struct drm_i915_gem_execbuffer2 *args) { - struct eb_objects *eb; - int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; - while (count > size) - count >>= 1; - eb = kmalloc(count*sizeof(struct hlist_head) + - sizeof(struct eb_objects), - M_DRM, M_WAITOK | M_ZERO); - if (eb == NULL) - return eb; - - eb->and = count - 1; + struct eb_objects *eb = NULL; + + if (args->flags & I915_EXEC_HANDLE_LUT) { + int size = args->buffer_count; + size *= sizeof(struct drm_i915_gem_object *); + size += sizeof(struct eb_objects); + eb = kmalloc(size, M_DRM, M_WAITOK); + } + + if (eb == NULL) { + int size = args->buffer_count; + int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; + BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head)); + while (count > 2*size) + count >>= 1; + eb = kmalloc(count*sizeof(struct hlist_head) + + sizeof(struct eb_objects), + M_DRM, M_WAITOK | M_ZERO); + if (eb == NULL) + return eb; + + eb->and = count - 1; + } else + eb->and = -args->buffer_count; + + INIT_LIST_HEAD(&eb->objects); return eb; } static void eb_reset(struct eb_objects *eb) { - memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); + if (eb->and >= 0) + memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); } -static void -eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj) +static int +eb_lookup_objects(struct eb_objects *eb, + struct drm_i915_gem_exec_object2 *exec, + const struct drm_i915_gem_execbuffer2 *args, + struct drm_file *file) { - hlist_add_head(&obj->exec_node, - &eb->buckets[obj->exec_handle & eb->and]); + int i; + + lockmgr(&file->table_lock, LK_EXCLUSIVE); + for (i = 0; i < args->buffer_count; i++) { + struct drm_i915_gem_object *obj; + + obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle)); + if (obj == NULL) { + lockmgr(&file->table_lock, LK_RELEASE); + DRM_DEBUG("Invalid object handle %d at index %d\n", + exec[i].handle, i); + return -ENOENT; + } + + if (!list_empty(&obj->exec_list)) { + lockmgr(&file->table_lock, LK_RELEASE); + DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", + obj, exec[i].handle, i); + return -EINVAL; + } + + drm_gem_object_reference(&obj->base); + list_add_tail(&obj->exec_list, &eb->objects); + + obj->exec_entry = &exec[i]; + if (eb->and < 0) { + eb->lut[i] = obj; + } else { + uint32_t handle = args->flags & I915_EXEC_HANDLE_LUT ? i : exec[i].handle; + obj->exec_handle = handle; + hlist_add_head(&obj->exec_node, + &eb->buckets[handle & eb->and]); + } + } + lockmgr(&file->table_lock, LK_RELEASE); + + return 0; } static struct drm_i915_gem_object * eb_get_object(struct eb_objects *eb, unsigned long handle) { - struct hlist_head *head; - struct hlist_node *node; - struct drm_i915_gem_object *obj; + if (eb->and < 0) { + if (handle >= -eb->and) + return NULL; + return eb->lut[handle]; + } else { + struct hlist_head *head; + struct hlist_node *node; - head = &eb->buckets[handle & eb->and]; - hlist_for_each(node, head) { - obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); - if (obj->exec_handle == handle) - return obj; - } + head = &eb->buckets[handle & eb->and]; + hlist_for_each(node, head) { + struct drm_i915_gem_object *obj; - return NULL; + obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); + if (obj->exec_handle == handle) + return obj; + } + return NULL; + } } static void eb_destroy(struct eb_objects *eb) { + while (!list_empty(&eb->objects)) { + struct drm_i915_gem_object *obj; + + obj = list_first_entry(&eb->objects, + struct drm_i915_gem_object, + exec_list); + list_del_init(&obj->exec_list); + drm_gem_object_unreference(&obj->base); + } drm_free(eb, M_DRM); } @@ -148,17 +222,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, reloc->write_domain); return ret; } - if (unlikely(reloc->write_domain && target_obj->pending_write_domain && - reloc->write_domain != target_obj->pending_write_domain)) { - DRM_DEBUG("Write domain conflict: " - "obj %p target %d offset %d " - "new %08x old %08x\n", - obj, reloc->target_handle, - (int) reloc->offset, - reloc->write_domain, - target_obj->pending_write_domain); - return ret; - } target_obj->pending_read_domains |= reloc->read_domains; target_obj->pending_write_domain |= reloc->write_domain; @@ -199,7 +262,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, if (ret) return ret; - vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]); + vaddr = kmap_atomic(i915_gem_object_get_page(obj, + reloc->offset >> PAGE_SHIFT)); *(uint32_t *)(vaddr + page_offset) = reloc->delta; kunmap_atomic(vaddr); } else { @@ -220,7 +284,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, ~PAGE_MASK), PAGE_SIZE, PAT_WRITE_COMBINING); reloc_entry = (uint32_t *)(reloc_page + (reloc->offset & PAGE_MASK)); - iowrite32(reloc->delta, reloc_entry); pmap_unmapdev((vm_offset_t)reloc_page, PAGE_SIZE); } @@ -296,8 +359,7 @@ i915_gem_execbuffer_relocate_object_slow(struct drm_i915_gem_object *obj, static int i915_gem_execbuffer_relocate(struct drm_device *dev, - struct eb_objects *eb, - struct list_head *objects) + struct eb_objects *eb) { struct drm_i915_gem_object *obj; int ret = 0; @@ -312,7 +374,7 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, #if 0 pagefault_disable(); #endif - list_for_each_entry(obj, objects, exec_list) { + list_for_each_entry(obj, &eb->objects, exec_list) { ret = i915_gem_execbuffer_relocate_object(obj, eb); if (ret) break; @@ -336,7 +398,8 @@ need_reloc_mappable(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *ring) + struct intel_ring_buffer *ring, + bool *need_reloc) { struct drm_i915_private *dev_priv = obj->base.dev->dev_private; struct drm_i915_gem_exec_object2 *entry = obj->exec_entry; @@ -377,7 +440,20 @@ i915_gem_execbuffer_reserve_object(struct drm_i915_gem_object *obj, obj->has_aliasing_ppgtt_mapping = 1; } - entry->offset = obj->gtt_offset; + if (entry->offset != obj->gtt_offset) { + entry->offset = obj->gtt_offset; + *need_reloc = true; + } + + if (entry->flags & EXEC_OBJECT_WRITE) { + obj->base.pending_read_domains = I915_GEM_DOMAIN_RENDER; + obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER; + } + + if (entry->flags & EXEC_OBJECT_NEEDS_GTT && + !obj->has_global_gtt_mapping) + i915_gem_gtt_bind_object(obj, obj->cache_level); + return 0; } @@ -403,7 +479,8 @@ i915_gem_execbuffer_unreserve_object(struct drm_i915_gem_object *obj) static int i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, struct drm_file *file, - struct list_head *objects) + struct list_head *objects, + bool *need_relocs) { struct drm_i915_gem_object *obj; struct list_head ordered_objects; @@ -431,7 +508,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, else list_move_tail(&obj->exec_list, &ordered_objects); - obj->base.pending_read_domains = 0; + obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND; obj->base.pending_write_domain = 0; obj->pending_fenced_gpu_access = false; } @@ -471,7 +548,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, (need_mappable && !obj->map_and_fenceable)) ret = i915_gem_object_unbind(obj); else - ret = i915_gem_execbuffer_reserve_object(obj, ring); + ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); if (ret) goto err; } @@ -481,7 +558,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring, if (obj->gtt_space) continue; - ret = i915_gem_execbuffer_reserve_object(obj, ring); + ret = i915_gem_execbuffer_reserve_object(obj, ring, need_relocs); if (ret) goto err; } @@ -501,28 +578,29 @@ err: /* Decrement pin count for bound objects */ static int i915_gem_execbuffer_relocate_slow(struct drm_device *dev, + struct drm_i915_gem_execbuffer2 *args, struct drm_file *file, struct intel_ring_buffer *ring, - struct list_head *objects, struct eb_objects *eb, - struct drm_i915_gem_exec_object2 *exec, - int count) + struct drm_i915_gem_exec_object2 *exec) { struct drm_i915_gem_relocation_entry *reloc; struct drm_i915_gem_object *obj; + bool need_relocs; int *reloc_offset; int i, total, ret; + int count = args->buffer_count; /* We may process another execbuffer during the unlock... */ - while (!list_empty(objects)) { - obj = list_first_entry(objects, + while (!list_empty(&eb->objects)) { + obj = list_first_entry(&eb->objects, struct drm_i915_gem_object, exec_list); list_del_init(&obj->exec_list); drm_gem_object_unreference(&obj->base); } - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); total = 0; for (i = 0; i < count; i++) @@ -533,7 +611,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, if (reloc == NULL || reloc_offset == NULL) { drm_free_large(reloc); drm_free_large(reloc_offset); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); return -ENOMEM; } @@ -548,7 +626,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, if (copy_from_user(reloc+total, user_relocs, exec[i].relocation_count * sizeof(*reloc))) { ret = -EFAULT; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); goto err; } @@ -566,7 +644,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, &invalid_offset, sizeof(invalid_offset))) { ret = -EFAULT; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); goto err; } } @@ -577,33 +655,22 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, ret = i915_mutex_lock_interruptible(dev); if (ret) { - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); goto err; } /* reacquire the objects */ eb_reset(eb); - for (i = 0; i < count; i++) { - obj = to_intel_bo(drm_gem_object_lookup(dev, file, - exec[i].handle)); - if (&obj->base == NULL) { - DRM_DEBUG("Invalid object handle %d at index %d\n", - exec[i].handle, i); - ret = -ENOENT; - goto err; - } - - list_add_tail(&obj->exec_list, objects); - obj->exec_handle = exec[i].handle; - obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); - } + ret = eb_lookup_objects(eb, exec, args, file); + if (ret) + goto err; - ret = i915_gem_execbuffer_reserve(ring, file, objects); + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); if (ret) goto err; - list_for_each_entry(obj, objects, exec_list) { + list_for_each_entry(obj, &eb->objects, exec_list) { int offset = obj->exec_entry - exec; ret = i915_gem_execbuffer_relocate_object_slow(obj, eb, reloc + reloc_offset[offset]); @@ -623,45 +690,12 @@ err: return ret; } -static int -i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips) -{ - u32 plane, flip_mask; - int ret; - - /* Check for any pending flips. As we only maintain a flip queue depth - * of 1, we can simply insert a WAIT for the next display flip prior - * to executing the batch and avoid stalling the CPU. - */ - - for (plane = 0; flips >> plane; plane++) { - if (((flips >> plane) & 1) == 0) - continue; - - if (plane) - flip_mask = MI_WAIT_FOR_PLANE_B_FLIP; - else - flip_mask = MI_WAIT_FOR_PLANE_A_FLIP; - - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; - - intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } - - return 0; -} - static int i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, struct list_head *objects) { struct drm_i915_gem_object *obj; uint32_t flush_domains = 0; - uint32_t flips = 0; int ret; list_for_each_entry(obj, objects, exec_list) { @@ -672,18 +706,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) i915_gem_clflush_object(obj); - if (obj->base.pending_write_domain) - flips |= atomic_read(&obj->pending_flip); - flush_domains |= obj->base.write_domain; } - if (flips) { - ret = i915_gem_execbuffer_wait_for_flips(ring, flips); - if (ret) - return ret; - } - if (flush_domains & I915_GEM_DOMAIN_CPU) i915_gem_chipset_flush(ring->dev); @@ -699,6 +724,9 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring, static bool i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec) { + if (exec->flags & __I915_EXEC_UNKNOWN_FLAGS) + return false; + return ((exec->batch_start_offset | exec->batch_len) & 0x7) == 0; } @@ -716,6 +744,9 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, #endif int length; /* limited by fault_in_pages_readable() */ + if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS) + return -EINVAL; + /* First check for malicious input causing overflow in * the worst case where we need to allocate the entire * relocation tree as a single array. @@ -727,9 +758,6 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, length = exec[i].relocation_count * sizeof(struct drm_i915_gem_relocation_entry); #if 0 - if (!access_ok(VERIFY_READ, ptr, length)) - return -EFAULT; - /* we may also need to update the presumed offsets */ if (!access_ok(VERIFY_WRITE, ptr, length)) return -EFAULT; @@ -749,8 +777,11 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, struct drm_i915_gem_object *obj; list_for_each_entry(obj, objects, exec_list) { - obj->base.read_domains = obj->base.pending_read_domains; + obj->base.write_domain = obj->base.pending_write_domain; + if (obj->base.write_domain == 0) + obj->base.pending_read_domains |= obj->base.read_domains; + obj->base.read_domains = obj->base.pending_read_domains; obj->fenced_gpu_access = obj->pending_fenced_gpu_access; i915_gem_object_move_to_active(obj, ring); @@ -760,6 +791,8 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects, if (obj->pin_count) /* check for potential scanout */ intel_mark_fb_busy(obj); } + + trace_i915_gem_object_change_domain(obj, old_read, old_write); } } @@ -807,21 +840,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_exec_object2 *exec) { drm_i915_private_t *dev_priv = dev->dev_private; - struct list_head objects; struct eb_objects *eb; struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; - u32 mask; - u32 flags; + u32 mask, flags; int ret, mode, i; + bool need_relocs; - if (!i915_gem_check_execbuffer(args)) { - DRM_DEBUG("execbuf with invalid offset/length\n"); + if (!i915_gem_check_execbuffer(args)) return -EINVAL; - } ret = validate_exec_list(exec, args->buffer_count); if (ret) @@ -912,6 +942,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, args->num_cliprects); return -EINVAL; } + cliprects = kmalloc(args->num_cliprects * sizeof(*cliprects), M_DRM, M_WAITOK | M_ZERO); if (cliprects == NULL) { @@ -933,64 +964,41 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; if (dev_priv->mm.suspended) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); ret = -EBUSY; goto pre_mutex_err; } - eb = eb_create(args->buffer_count); + eb = eb_create(args); if (eb == NULL) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); ret = -ENOMEM; goto pre_mutex_err; } /* Look up object handles */ - INIT_LIST_HEAD(&objects); - for (i = 0; i < args->buffer_count; i++) { - struct drm_i915_gem_object *obj; - - obj = to_intel_bo(drm_gem_object_lookup(dev, file, - exec[i].handle)); - if (&obj->base == NULL) { - DRM_DEBUG("Invalid object handle %d at index %d\n", - exec[i].handle, i); - /* prevent error path from reading uninitialized data */ - ret = -ENOENT; - goto err; - } - - if (!list_empty(&obj->exec_list)) { - DRM_DEBUG("Object %p [handle %d, index %d] appears more than once in object list\n", - obj, exec[i].handle, i); - ret = -EINVAL; - goto err; - } - - list_add_tail(&obj->exec_list, &objects); - obj->exec_handle = exec[i].handle; - obj->exec_entry = &exec[i]; - eb_add_object(eb, obj); - } + ret = eb_lookup_objects(eb, exec, args, file); + if (ret) + goto err; /* take note of the batch buffer before we might reorder the lists */ - batch_obj = list_entry(objects.prev, + batch_obj = list_entry(eb->objects.prev, struct drm_i915_gem_object, exec_list); /* Move the objects en-masse into the GTT, evicting if necessary. */ - ret = i915_gem_execbuffer_reserve(ring, file, &objects); + need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; + ret = i915_gem_execbuffer_reserve(ring, file, &eb->objects, &need_relocs); if (ret) goto err; /* The objects are in their final locations, apply the relocations. */ - ret = i915_gem_execbuffer_relocate(dev, eb, &objects); + if (need_relocs) + ret = i915_gem_execbuffer_relocate(dev, eb); if (ret) { if (ret == -EFAULT) { - ret = i915_gem_execbuffer_relocate_slow(dev, file, ring, - &objects, eb, - exec, - args->buffer_count); + ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, + eb, exec); DRM_LOCK_ASSERT(dev); } if (ret) @@ -1012,7 +1020,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping) i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level); - ret = i915_gem_execbuffer_move_to_gpu(ring, &objects); + ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->objects); if (ret) goto err; @@ -1064,22 +1072,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } - i915_gem_execbuffer_move_to_active(&objects, ring); + trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags); + + i915_gem_execbuffer_move_to_active(&eb->objects, ring); i915_gem_execbuffer_retire_commands(dev, file, ring); err: eb_destroy(eb); - while (!list_empty(&objects)) { - struct drm_i915_gem_object *obj; - - obj = list_first_entry(&objects, - struct drm_i915_gem_object, - exec_list); - list_del_init(&obj->exec_list); - drm_gem_object_unreference(&obj->base); - } - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); pre_mutex_err: drm_free(cliprects, M_DRM); @@ -1115,7 +1116,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, drm_free_large(exec2_list); return -ENOMEM; } - ret = copy_from_user(exec_list, (void __user *)(uintptr_t)args->buffers_ptr, sizeof(*exec_list) * args->buffer_count); diff --git a/sys/dev/drm/i915/i915_gem_gtt.c b/sys/dev/drm/i915/i915_gem_gtt.c index 2b447c1e10..21105f950d 100644 --- a/sys/dev/drm/i915/i915_gem_gtt.c +++ b/sys/dev/drm/i915/i915_gem_gtt.c @@ -45,9 +45,9 @@ typedef uint32_t gtt_pte_t; #define GEN6_PTE_CACHE_LLC_MLC (3 << 1) #define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr) -static inline gtt_pte_t pte_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) +static inline gtt_pte_t gen6_pte_encode(struct drm_device *dev, + dma_addr_t addr, + enum i915_cache_level level) { gtt_pte_t pte = GEN6_PTE_VALID; pte |= GEN6_PTE_ADDR_ENCODE(addr); @@ -78,7 +78,7 @@ static inline gtt_pte_t pte_encode(struct drm_device *dev, } /* PPGTT support for Sandybdrige/Gen6 and later */ -static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, +static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, unsigned num_entries) { @@ -88,8 +88,9 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; unsigned last_pte, i; - scratch_pte = pte_encode(ppgtt->dev, ppgtt->scratch_page_dma_addr, - I915_CACHE_LLC); + scratch_pte = gen6_pte_encode(ppgtt->dev, + ppgtt->scratch_page_dma_addr, + I915_CACHE_LLC); while (num_entries) { last_pte = first_pte + num_entries; @@ -109,10 +110,74 @@ static void i915_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt, } } -int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt, + struct sg_table *pages, + unsigned first_entry, + enum i915_cache_level cache_level) { + gtt_pte_t *pt_vaddr; + unsigned act_pd = first_entry / I915_PPGTT_PT_ENTRIES; + unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES; + unsigned i, j, m, segment_len; + dma_addr_t page_addr; + struct scatterlist *sg; + + /* init sg walking */ + sg = pages->sgl; + i = 0; + segment_len = sg_dma_len(sg) >> PAGE_SHIFT; + m = 0; + + while (i < pages->nents) { + pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pd]); + + for (j = first_pte; j < I915_PPGTT_PT_ENTRIES; j++) { + page_addr = sg_dma_address(sg) + (m << PAGE_SHIFT); + pt_vaddr[j] = gen6_pte_encode(ppgtt->dev, page_addr, + cache_level); + + /* grab the next page */ + if (++m == segment_len) { + if (++i == pages->nents) + break; + + sg = sg_next(sg); + segment_len = sg_dma_len(sg) >> PAGE_SHIFT; + m = 0; + } + } + + kunmap_atomic(pt_vaddr); + + first_pte = 0; + act_pd++; + } +} + +static void gen6_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) +{ +#if 0 + int i; + + if (ppgtt->pt_dma_addr) { + for (i = 0; i < ppgtt->num_pd_entries; i++) + pci_unmap_page(ppgtt->dev->pdev, + ppgtt->pt_dma_addr[i], + 4096, PCI_DMA_BIDIRECTIONAL); + } + + kfree(ppgtt->pt_dma_addr); + for (i = 0; i < ppgtt->num_pd_entries; i++) + __free_page(ppgtt->pt_pages[i]); + kfree(ppgtt->pt_pages); + kfree(ppgtt); +#endif +} + +static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) +{ + struct drm_device *dev = ppgtt->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct i915_hw_ppgtt *ppgtt; unsigned first_pd_entry_in_global_pt; int i; int ret = -ENOMEM; @@ -121,18 +186,16 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) * entries. For aliasing ppgtt support we just steal them at the end for * now. */ - first_pd_entry_in_global_pt = 512 * 1024 - I915_PPGTT_PD_ENTRIES; + first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt); - ppgtt = kmalloc(sizeof(*ppgtt), M_DRM, M_WAITOK | M_ZERO); - if (!ppgtt) - return ret; - - ppgtt->dev = dev; ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES; + ppgtt->clear_range = gen6_ppgtt_clear_range; + ppgtt->insert_entries = gen6_ppgtt_insert_entries; + ppgtt->cleanup = gen6_ppgtt_cleanup; ppgtt->pt_pages = kmalloc(sizeof(vm_page_t) * ppgtt->num_pd_entries, M_DRM, M_WAITOK | M_ZERO); if (!ppgtt->pt_pages) - goto err_ppgtt; + return -ENOMEM; for (i = 0; i < ppgtt->num_pd_entries; i++) { ppgtt->pt_pages[i] = vm_page_alloc(NULL, 0, @@ -141,28 +204,55 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) goto err_pt_alloc; } - ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma; + ppgtt->scratch_page_dma_addr = dev_priv->gtt.scratch_page_dma; - i915_ppgtt_clear_range(ppgtt, 0, - ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); + ppgtt->clear_range(ppgtt, 0, + ppgtt->num_pd_entries*I915_PPGTT_PT_ENTRIES); ppgtt->pd_offset = (first_pd_entry_in_global_pt)*sizeof(gtt_pte_t); - dev_priv->mm.aliasing_ppgtt = ppgtt; - return 0; - err_pt_alloc: dev_priv->mm.aliasing_ppgtt = ppgtt; i915_gem_cleanup_aliasing_ppgtt(dev); - return (-ENOMEM); -err_ppgtt: - kfree(ppgtt, M_DRM); + + return ret; +} + +static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt; + int ret; + + ppgtt = kmalloc(sizeof(*ppgtt), M_DRM, M_WAITOK | M_ZERO); + if (!ppgtt) + return -ENOMEM; + + ppgtt->dev = dev; + + ret = gen6_ppgtt_init(ppgtt); + if (ret) + kfree(ppgtt, M_DRM); + else + dev_priv->mm.aliasing_ppgtt = ppgtt; return ret; } +void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + + if (!ppgtt) + return; + + ppgtt->cleanup(ppgtt); +} + +#if 0 void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -185,6 +275,7 @@ void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev) drm_free(ppgtt->pt_pages, M_DRM); drm_free(ppgtt, M_DRM); } +#endif static void i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, @@ -205,7 +296,7 @@ i915_ppgtt_insert_pages(struct i915_hw_ppgtt *ppgtt, unsigned first_entry, for (i = first_pte; i < last_pte; i++) { page_addr = VM_PAGE_TO_PHYS(*pages); - pt_vaddr[i] = pte_encode(ppgtt->dev, page_addr, + pt_vaddr[i] = gen6_pte_encode(ppgtt->dev, page_addr, cache_level); pages++; @@ -230,9 +321,9 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt, void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt, struct drm_i915_gem_object *obj) { - i915_ppgtt_clear_range(ppgtt, - obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); + ppgtt->clear_range(ppgtt, + obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); } void i915_gem_init_ppgtt(struct drm_device *dev) @@ -291,11 +382,27 @@ void i915_gem_init_ppgtt(struct drm_device *dev) } } +extern int intel_iommu_gfx_mapped; +/* Certain Gen5 chipsets require require idling the GPU before + * unmapping anything from the GTT when VT-d is enabled. + */ +static inline bool needs_idle_maps(struct drm_device *dev) +{ +#ifdef CONFIG_INTEL_IOMMU + /* Query intel_iommu to see if we need the workaround. Presumably that + * was loaded first. + */ + if (IS_GEN5(dev) && IS_MOBILE(dev) && intel_iommu_gfx_mapped) + return true; +#endif + return false; +} + static bool do_idling(struct drm_i915_private *dev_priv) { bool ret = dev_priv->mm.interruptible; - if (unlikely(dev_priv->mm.gtt->do_idle_maps)) { + if (unlikely(dev_priv->gtt.do_idle_maps)) { dev_priv->mm.interruptible = false; if (i915_gpu_idle(dev_priv->dev)) { DRM_ERROR("Couldn't idle GPU\n"); @@ -309,45 +416,18 @@ static bool do_idling(struct drm_i915_private *dev_priv) static void undo_idling(struct drm_i915_private *dev_priv, bool interruptible) { - if (unlikely(dev_priv->mm.gtt->do_idle_maps)) + if (unlikely(dev_priv->gtt.do_idle_maps)) dev_priv->mm.interruptible = interruptible; } - -static void i915_ggtt_clear_range(struct drm_device *dev, - unsigned first_entry, - unsigned num_entries) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - gtt_pte_t scratch_pte; - gtt_pte_t __iomem *gtt_base = dev_priv->mm.gtt->gtt + first_entry; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; - int i; - - if (INTEL_INFO(dev)->gen < 6) { - intel_gtt_clear_range(first_entry, num_entries); - return; - } - - if (WARN(num_entries > max_entries, - "First entry = %d; Num entries = %d (max=%d)\n", - first_entry, num_entries, max_entries)) - num_entries = max_entries; - - scratch_pte = pte_encode(dev, dev_priv->mm.gtt->scratch_page_dma, I915_CACHE_LLC); - for (i = 0; i < num_entries; i++) - iowrite32(scratch_pte, >t_base[i]); - readl(gtt_base); -} - void i915_gem_restore_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; /* First fill our portion of the GTT with scratch pages */ - i915_ggtt_clear_range(dev, dev_priv->mm.gtt_start / PAGE_SIZE, - (dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE); + dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE, + dev_priv->gtt.total / PAGE_SIZE); list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) { i915_gem_clflush_object(obj); @@ -370,6 +450,7 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) return 0; } +#endif /* * Binds an object into the global gtt with the specified cache level. The object @@ -377,16 +458,16 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) * within the global GTT as well as accessible by the GPU through the GMADR * mapped BAR (dev_priv->mm.gtt->gtt). */ -static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, - enum i915_cache_level level) +static void gen6_ggtt_insert_entries(struct drm_device *dev, + struct sg_table *st, + unsigned int first_entry, + enum i915_cache_level level) { - struct drm_device *dev = obj->base.dev; +#if 0 struct drm_i915_private *dev_priv = dev->dev_private; - struct sg_table *st = obj->pages; struct scatterlist *sg = st->sgl; - const int first_entry = obj->gtt_space->start >> PAGE_SHIFT; - const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; - gtt_pte_t __iomem *gtt_entries = dev_priv->mm.gtt->gtt + first_entry; + gtt_pte_t __iomem *gtt_entries = + (gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry; int unused, i = 0; unsigned int len, m = 0; dma_addr_t addr; @@ -395,14 +476,12 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, len = sg_dma_len(sg) >> PAGE_SHIFT; for (m = 0; m < len; m++) { addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - iowrite32(pte_encode(dev, addr, level), >t_entries[i]); + iowrite32(gen6_pte_encode(dev, addr, level), + >t_entries[i]); i++; } } - BUG_ON(i > max_entries); - BUG_ON(i != obj->base.size / PAGE_SIZE); - /* XXX: This serves as a posting read to make sure that the PTE has * actually been updated. There is some concern that even though * registers and PTEs are within the same BAR that they are potentially @@ -410,7 +489,8 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, * hardware should work, we must keep this posting read for paranoia. */ if (i != 0) - WARN_ON(readl(>t_entries[i-1]) != pte_encode(dev, addr, level)); + WARN_ON(readl(>t_entries[i-1]) + != gen6_pte_encode(dev, addr, level)); /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates @@ -418,8 +498,50 @@ static void gen6_ggtt_bind_object(struct drm_i915_gem_object *obj, */ I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); POSTING_READ(GFX_FLSH_CNTL_GEN6); +#endif } + +static void gen6_ggtt_clear_range(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + gtt_pte_t scratch_pte; + gtt_pte_t __iomem *gtt_base = (gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry; + const int max_entries = dev_priv->mm.gtt->gtt_total_entries - first_entry; + int i; + + if (WARN(num_entries > max_entries, + "First entry = %d; Num entries = %d (max=%d)\n", + first_entry, num_entries, max_entries)) + num_entries = max_entries; + + scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma, + I915_CACHE_LLC); + for (i = 0; i < num_entries; i++) + iowrite32(scratch_pte, >t_base[i]); + readl(gtt_base); +} + +static void i915_ggtt_insert_entries(struct drm_device *dev, + struct sg_table *st, + unsigned int pg_start, + enum i915_cache_level cache_level) +{ +#if 0 + unsigned int flags = (cache_level == I915_CACHE_NONE) ? + AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY; + + intel_gtt_insert_sg_entries(st, pg_start, flags); #endif +} + +static void i915_ggtt_clear_range(struct drm_device *dev, + unsigned int first_entry, + unsigned int num_entries) +{ + intel_gtt_clear_range(first_entry, num_entries); +} void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj, enum i915_cache_level cache_level) @@ -436,14 +558,11 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - bool interruptible; - - interruptible = do_idling(dev_priv); - intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT, - obj->base.size >> PAGE_SHIFT); + dev_priv->gtt.gtt_clear_range(obj->base.dev, + obj->gtt_space->start >> PAGE_SHIFT, + obj->base.size >> PAGE_SHIFT); - undo_idling(dev_priv, interruptible); obj->has_global_gtt_mapping = 0; } @@ -481,17 +600,26 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node, *end -= 4096; } } - -void i915_gem_init_global_gtt(struct drm_device *dev, - unsigned long start, - unsigned long mappable_end, - unsigned long end) +void i915_gem_setup_global_gtt(struct drm_device *dev, + unsigned long start, + unsigned long mappable_end, + unsigned long end) { + /* Let GEM Manage all of the aperture. + * + * However, leave one page at the end still bound to the scratch page. + * There are a number of places where the hardware apparently prefetches + * past the end of the object, and we've seen multiple hangs with the + * GPU head pointer stuck in a batchbuffer bound at the last page of the + * aperture. One page should be enough to keep any prefetching inside + * of the aperture. + */ drm_i915_private_t *dev_priv = dev->dev_private; - unsigned long mappable; int error; + BUG_ON(mappable_end > end); + mappable = min(end, mappable_end) - start; /* Substract the guard page ... */ @@ -499,11 +627,9 @@ void i915_gem_init_global_gtt(struct drm_device *dev, if (!HAS_LLC(dev)) dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust; - dev_priv->mm.gtt_start = start; - dev_priv->mm.gtt_mappable_end = mappable_end; - dev_priv->mm.gtt_end = end; - dev_priv->mm.gtt_total = end - start; - dev_priv->mm.mappable_gtt_total = mappable; + dev_priv->gtt.start = start; + dev_priv->gtt.mappable_end = mappable_end; + dev_priv->gtt.total = end - start; /* ... but ensure that we clear the entire range. */ intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE); @@ -514,6 +640,57 @@ void i915_gem_init_global_gtt(struct drm_device *dev, dev->agp->base + start + mappable, VM_MEMATTR_WRITE_COMBINING); } +static bool +intel_enable_ppgtt(struct drm_device *dev) +{ + if (i915_enable_ppgtt >= 0) + return i915_enable_ppgtt; + +#ifdef CONFIG_INTEL_IOMMU + /* Disable ppgtt on SNB if VT-d is on. */ + if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) + return false; +#endif + + return true; +} + +void i915_gem_init_global_gtt(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long gtt_size, mappable_size; + int ret; + + gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT; + mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + + if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) { + /* PPGTT pdes are stolen from global gtt ptes, so shrink the + * aperture accordingly when using aliasing ppgtt. */ + gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE; + + i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); + + ret = i915_gem_init_aliasing_ppgtt(dev); + if (ret) { + DRM_UNLOCK(dev); + return; + } + } else { + /* Let GEM Manage all of the aperture. + * + * However, leave one page at the end still bound to the scratch + * page. There are a number of places where the hardware + * apparently prefetches past the end of the object, and we've + * seen multiple hangs with the GPU head pointer stuck in a + * batchbuffer bound at the last page of the aperture. One page + * should be enough to keep any prefetching inside of the + * aperture. + */ + i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); + } +} + int i915_gem_gtt_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -527,6 +704,12 @@ int i915_gem_gtt_init(struct drm_device *dev) DRM_ERROR("Failed to initialize GTT\n"); return -ENODEV; } + + dev_priv->gtt.do_idle_maps = needs_idle_maps(dev); + + dev_priv->gtt.gtt_clear_range = i915_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = i915_ggtt_insert_entries; + return 0; } @@ -534,14 +717,13 @@ int i915_gem_gtt_init(struct drm_device *dev) if (!dev_priv->mm.gtt) return -ENOMEM; -#ifdef CONFIG_INTEL_IOMMU - dev_priv->mm.gtt->needs_dmar = 1; -#endif - /* GMADR is the PCI aperture used by SW to access tiled GFX surfaces in a linear fashion. */ DRM_INFO("Memory usable by graphics device = %dM\n", dev_priv->mm.gtt->gtt_total_entries >> 8); DRM_DEBUG_DRIVER("GMADR size = %dM\n", dev_priv->mm.gtt->gtt_mappable_entries >> 8); DRM_DEBUG_DRIVER("GTT stolen size = %dM\n", dev_priv->mm.gtt->stolen_size >> 20); + dev_priv->gtt.gtt_clear_range = gen6_ggtt_clear_range; + dev_priv->gtt.gtt_insert_entries = gen6_ggtt_insert_entries; + return 0; } diff --git a/sys/dev/drm/i915/i915_gem_stolen.c b/sys/dev/drm/i915/i915_gem_stolen.c new file mode 100644 index 0000000000..ca378d63e8 --- /dev/null +++ b/sys/dev/drm/i915/i915_gem_stolen.c @@ -0,0 +1,197 @@ +/* + * Copyright © 2008-2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * Chris Wilson + * + */ + +#include +#include +#include "i915_drv.h" + +/* + * The BIOS typically reserves some of the system's memory for the exclusive + * use of the integrated graphics. This memory is no longer available for + * use by the OS and so the user finds that his system has less memory + * available than he put in. We refer to this memory as stolen. + * + * The BIOS will allocate its framebuffer from the stolen memory. Our + * goal is try to reuse that object for our own fbcon which must always + * be available for panics. Anything else we can reuse the stolen memory + * for is a boon. + */ + +static unsigned long i915_stolen_to_physical(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct pci_dev *pdev = dev_priv->bridge_dev; + u32 base; + + /* On the machines I have tested the Graphics Base of Stolen Memory + * is unreliable, so on those compute the base by subtracting the + * stolen memory from the Top of Low Usable DRAM which is where the + * BIOS places the graphics stolen memory. + * + * On gen2, the layout is slightly different with the Graphics Segment + * immediately following Top of Memory (or Top of Usable DRAM). Note + * it appears that TOUD is only reported by 865g, so we just use the + * top of memory as determined by the e820 probe. + * + * XXX gen2 requires an unavailable symbol and 945gm fails with + * its value of TOLUD. + */ + base = 0; + if (INTEL_INFO(dev)->gen >= 6) { + /* Read Base Data of Stolen Memory Register (BDSM) directly. + * Note that there is also a MCHBAR miror at 0x1080c0 or + * we could use device 2:0x5c instead. + */ + pci_read_config_dword(pdev, 0xB0, &base); + base &= ~4095; /* lower bits used for locking register */ + } else if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) { + /* Read Graphics Base of Stolen Memory directly */ + pci_read_config_dword(pdev, 0xA4, &base); +#if 0 + } else if (IS_GEN3(dev)) { + u8 val; + /* Stolen is immediately below Top of Low Usable DRAM */ + pci_read_config_byte(pdev, 0x9c, &val); + base = val >> 3 << 27; + base -= dev_priv->mm.gtt->stolen_size; + } else { + /* Stolen is immediately above Top of Memory */ + base = max_low_pfn_mapped << PAGE_SHIFT; +#endif + } + + return base; +} + +static int i915_setup_compression(struct drm_device *dev, int size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mm_node *compressed_fb, *compressed_llb = NULL; + + /* Try to over-allocate to reduce reallocations and fragmentation */ + compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, + size <<= 1, 4096, 0); + if (!compressed_fb) + compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, + size >>= 1, 4096, 0); + if (compressed_fb) + compressed_fb = drm_mm_get_block(compressed_fb, size, 4096); + if (!compressed_fb) + goto err; + + if (HAS_PCH_SPLIT(dev)) + I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); + else if (IS_GM45(dev)) { + I915_WRITE(DPFC_CB_BASE, compressed_fb->start); + } else { + compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen, + 4096, 4096, 0); + if (compressed_llb) + compressed_llb = drm_mm_get_block(compressed_llb, + 4096, 4096); + if (!compressed_llb) + goto err_fb; + + dev_priv->compressed_llb = compressed_llb; + + I915_WRITE(FBC_CFB_BASE, + dev_priv->mm.stolen_base + compressed_fb->start); + I915_WRITE(FBC_LL_BASE, + dev_priv->mm.stolen_base + compressed_llb->start); + } + + dev_priv->compressed_fb = compressed_fb; + dev_priv->cfb_size = size; + + DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", + size); + + return 0; + +err_fb: + drm_mm_put_block(compressed_fb); +err: + return -ENOSPC; +} + +int i915_gem_stolen_setup_compression(struct drm_device *dev, int size) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->mm.stolen_base == 0) + return -ENODEV; + + if (size < dev_priv->cfb_size) + return 0; + + /* Release any current block */ + i915_gem_stolen_cleanup_compression(dev); + + return i915_setup_compression(dev, size); +} + +void i915_gem_stolen_cleanup_compression(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->cfb_size == 0) + return; + + if (dev_priv->compressed_fb) + drm_mm_put_block(dev_priv->compressed_fb); + + if (dev_priv->compressed_llb) + drm_mm_put_block(dev_priv->compressed_llb); + + dev_priv->cfb_size = 0; +} + +void i915_gem_cleanup_stolen(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + i915_gem_stolen_cleanup_compression(dev); + drm_mm_takedown(&dev_priv->mm.stolen); +} + +int i915_gem_init_stolen(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->mm.stolen_base = i915_stolen_to_physical(dev); + if (dev_priv->mm.stolen_base == 0) + return 0; + + DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n", + dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base); + + /* Basic memrange allocator for stolen space */ + drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size); + + return 0; +} diff --git a/sys/dev/drm/i915/i915_gem_tiling.c b/sys/dev/drm/i915/i915_gem_tiling.c index c7a2509d56..ce918e25a5 100644 --- a/sys/dev/drm/i915/i915_gem_tiling.c +++ b/sys/dev/drm/i915/i915_gem_tiling.c @@ -272,18 +272,7 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) return false; } - /* - * Previous chips need to be aligned to the size of the smallest - * fence register that can contain the object. - */ - if (INTEL_INFO(obj->base.dev)->gen == 3) - size = 1024*1024; - else - size = 512*1024; - - while (size < obj->base.size) - size <<= 1; - + size = i915_gem_get_gtt_size(obj->base.dev, obj->base.size, tiling_mode); if (obj->gtt_space->size != size) return false; @@ -350,7 +339,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, } } - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); if (args->tiling_mode != obj->tiling_mode || args->stride != obj->stride) { /* We need to rebind the object if its current allocation @@ -368,15 +357,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, obj->map_and_fenceable = obj->gtt_space == NULL || - (obj->gtt_offset + obj->base.size <= dev_priv->mm.gtt_mappable_end && + (obj->gtt_offset + obj->base.size <= dev_priv->gtt.mappable_end && i915_gem_object_fence_ok(obj, args->tiling_mode)); /* Rebind if we need a change of alignment */ if (!obj->map_and_fenceable) { u32 unfenced_alignment = - i915_gem_get_unfenced_gtt_alignment(dev, - obj->base.size, - args->tiling_mode); + i915_gem_get_gtt_alignment(dev, obj->base.size, + args->tiling_mode, + false); if (obj->gtt_offset & (unfenced_alignment - 1)) ret = i915_gem_object_unbind(obj); } @@ -396,8 +385,20 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, /* we have to maintain this existing ABI... */ args->stride = obj->stride; args->tiling_mode = obj->tiling_mode; + + /* Try to preallocate memory required to save swizzling on put-pages */ + if (i915_gem_object_needs_bit17_swizzle(obj)) { + if (obj->bit_17 == NULL) { + obj->bit_17 = kmalloc(BITS_TO_LONGS(obj->base.size >> PAGE_SHIFT) * + sizeof(long), M_DRM, M_WAITOK); + } + } else { + drm_free(obj->bit_17, M_DRM); + obj->bit_17 = NULL; + } + drm_gem_object_unreference(&obj->base); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -417,7 +418,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, if (&obj->base == NULL) return -ENOENT; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); args->tiling_mode = obj->tiling_mode; switch (obj->tiling_mode) { @@ -441,7 +442,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10; drm_gem_object_unreference(&obj->base); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return 0; } diff --git a/sys/dev/drm/i915/i915_irq.c b/sys/dev/drm/i915/i915_irq.c index c6f649af0b..42f76183b5 100644 --- a/sys/dev/drm/i915/i915_irq.c +++ b/sys/dev/drm/i915/i915_irq.c @@ -281,22 +281,23 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; - lockmgr(&mode_config->mutex, LK_EXCLUSIVE); + /* HPD irq before everything is fully set up. */ + if (!dev_priv->enable_hotplug_processing) + return; + + mutex_lock(&mode_config->mutex); DRM_DEBUG_KMS("running encoder hotplug functions\n"); list_for_each_entry(encoder, &mode_config->encoder_list, base.head) if (encoder->hot_plug) encoder->hot_plug(encoder); - lockmgr(&mode_config->mutex, LK_RELEASE); + mutex_unlock(&mode_config->mutex); /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } -/* defined intel_pm.c */ -extern struct lock mchdev_lock; - static void ironlake_handle_rps_change(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -346,8 +347,8 @@ static void notify_ring(struct drm_device *dev, wake_up_all(&ring->irq_queue); if (i915_enable_hangcheck) { - dev_priv->hangcheck_count = 0; - mod_timer(&dev_priv->hangcheck_timer, + dev_priv->gpu_error.hangcheck_count = 0; + mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } } @@ -369,7 +370,7 @@ static void gen6_pm_rps_work(struct work_struct *work) if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) return; - lockmgr(&dev_priv->rps.hw_lock, LK_EXCLUSIVE); + mutex_lock(&dev_priv->rps.hw_lock); if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) new_delay = dev_priv->rps.cur_delay + 1; @@ -384,7 +385,7 @@ static void gen6_pm_rps_work(struct work_struct *work) gen6_set_rps(dev_priv->dev, new_delay); } - lockmgr(&dev_priv->rps.hw_lock, LK_RELEASE); + mutex_unlock(&dev_priv->rps.hw_lock); } @@ -402,13 +403,14 @@ static void ivybridge_parity_work(struct work_struct *work) drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, l3_parity.error_work); u32 error_status, row, bank, subbank; + char *parity_event[5]; uint32_t misccpctl; /* We must turn off DOP level clock gating to access the L3 registers. * In order to prevent a get/put style interface, acquire struct mutex * any time we access those registers. */ - DRM_LOCK(dev_priv->dev); + mutex_lock(&dev_priv->dev->struct_mutex); misccpctl = I915_READ(GEN7_MISCCPCTL); I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE); @@ -430,7 +432,10 @@ static void ivybridge_parity_work(struct work_struct *work) I915_WRITE(GTIMR, dev_priv->gt_irq_mask); lockmgr(&dev_priv->irq_lock, LK_RELEASE); - DRM_UNLOCK(dev_priv->dev); + mutex_unlock(&dev_priv->dev->struct_mutex); + + parity_event[0] = "L3_PARITY_ERROR=1"; + parity_event[4] = NULL; DRM_DEBUG("Parity error: Row = %d, Bank = %d, Sub bank = %d.\n", row, bank, subbank); @@ -498,6 +503,20 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv, queue_work(dev_priv->wq, &dev_priv->rps.work); } +static void gmbus_irq_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + + wake_up_all(&dev_priv->gmbus_wait_queue); +} + +static void dp_aux_irq_handler(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private; + + wake_up_all(&dev_priv->gmbus_wait_queue); +} + static irqreturn_t valleyview_irq_handler(void *arg) { struct drm_device *dev = (struct drm_device *) arg; @@ -505,7 +524,6 @@ static irqreturn_t valleyview_irq_handler(void *arg) u32 iir, gt_iir, pm_iir; int pipe; u32 pipe_stats[I915_MAX_PIPES]; - bool blc_event; atomic_inc(&dev_priv->irq_received); @@ -560,8 +578,8 @@ static irqreturn_t valleyview_irq_handler(void *arg) I915_READ(PORT_HOTPLUG_STAT); } - if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS) - blc_event = true; + if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) + gmbus_irq_handler(dev); if (pm_iir & GEN6_PM_DEFERRED_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); @@ -588,8 +606,11 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) (pch_iir & SDE_AUDIO_POWER_MASK) >> SDE_AUDIO_POWER_SHIFT); + if (pch_iir & SDE_AUX_MASK) + dp_aux_irq_handler(dev); + if (pch_iir & SDE_GMBUS) - DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); + gmbus_irq_handler(dev); if (pch_iir & SDE_AUDIO_HDCP_MASK) DRM_DEBUG_DRIVER("PCH HDCP audio interrupt\n"); @@ -632,10 +653,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) SDE_AUDIO_POWER_SHIFT_CPT); if (pch_iir & SDE_AUX_MASK_CPT) - DRM_DEBUG_DRIVER("AUX channel interrupt\n"); + dp_aux_irq_handler(dev); if (pch_iir & SDE_GMBUS_CPT) - DRM_DEBUG_DRIVER("PCH GMBUS interrupt\n"); + gmbus_irq_handler(dev); if (pch_iir & SDE_AUDIO_CP_REQ_CPT) DRM_DEBUG_DRIVER("Audio CP request interrupt\n"); @@ -654,7 +675,7 @@ static irqreturn_t ivybridge_irq_handler(void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 de_iir, gt_iir, de_ier, pm_iir; + u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; int i; atomic_inc(&dev_priv->irq_received); @@ -663,6 +684,15 @@ static irqreturn_t ivybridge_irq_handler(void *arg) de_ier = I915_READ(DEIER); I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); + /* Disable south interrupts. We'll only write to SDEIIR once, so further + * interrupts will will be stored on its back queue, and then we'll be + * able to process them after we restore SDEIER (as soon as we restore + * it, we'll get an interrupt if SDEIIR still has something to process + * due to its back queue). */ + sde_ier = I915_READ(SDEIER); + I915_WRITE(SDEIER, 0); + POSTING_READ(SDEIER); + gt_iir = I915_READ(GTIIR); if (gt_iir) { snb_gt_irq_handler(dev, dev_priv, gt_iir); @@ -671,6 +701,9 @@ static irqreturn_t ivybridge_irq_handler(void *arg) de_iir = I915_READ(DEIIR); if (de_iir) { + if (de_iir & DE_AUX_CHANNEL_A_IVB) + dp_aux_irq_handler(dev); + if (de_iir & DE_GSE_IVB) intel_opregion_gse_intr(dev); @@ -705,6 +738,8 @@ static irqreturn_t ivybridge_irq_handler(void *arg) I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); + I915_WRITE(SDEIER, sde_ier); + POSTING_READ(SDEIER); } static void ilk_gt_irq_handler(struct drm_device *dev, @@ -721,7 +756,7 @@ static irqreturn_t ironlake_irq_handler(void *arg) { struct drm_device *dev = (struct drm_device *) arg; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir; + u32 de_iir, gt_iir, de_ier, pm_iir, sde_ier; atomic_inc(&dev_priv->irq_received); @@ -730,13 +765,20 @@ static irqreturn_t ironlake_irq_handler(void *arg) I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL); POSTING_READ(DEIER); + /* Disable south interrupts. We'll only write to SDEIIR once, so further + * interrupts will will be stored on its back queue, and then we'll be + * able to process them after we restore SDEIER (as soon as we restore + * it, we'll get an interrupt if SDEIIR still has something to process + * due to its back queue). */ + sde_ier = I915_READ(SDEIER); + I915_WRITE(SDEIER, 0); + POSTING_READ(SDEIER); + de_iir = I915_READ(DEIIR); gt_iir = I915_READ(GTIIR); - pch_iir = I915_READ(SDEIIR); pm_iir = I915_READ(GEN6_PMIIR); - if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && - (!IS_GEN6(dev) || pm_iir == 0)) + if (de_iir == 0 && gt_iir == 0 && (!IS_GEN6(dev) || pm_iir == 0)) goto done; if (IS_GEN5(dev)) @@ -744,6 +786,9 @@ static irqreturn_t ironlake_irq_handler(void *arg) else snb_gt_irq_handler(dev, dev_priv, gt_iir); + if (de_iir & DE_AUX_CHANNEL_A) + dp_aux_irq_handler(dev); + if (de_iir & DE_GSE) intel_opregion_gse_intr(dev); @@ -765,10 +810,15 @@ static irqreturn_t ironlake_irq_handler(void *arg) /* check event from PCH */ if (de_iir & DE_PCH_EVENT) { + u32 pch_iir = I915_READ(SDEIIR); + if (HAS_PCH_CPT(dev)) cpt_irq_handler(dev, pch_iir); else ibx_irq_handler(dev, pch_iir); + + /* should clear PCH hotplug event before clear CPU irq */ + I915_WRITE(SDEIIR, pch_iir); } if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT) @@ -777,8 +827,6 @@ static irqreturn_t ironlake_irq_handler(void *arg) if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) gen6_queue_rps_work(dev_priv, pm_iir); - /* should clear PCH hotplug event before clear CPU irq */ - I915_WRITE(SDEIIR, pch_iir); I915_WRITE(GTIIR, gt_iir); I915_WRITE(DEIIR, de_iir); I915_WRITE(GEN6_PMIIR, pm_iir); @@ -786,6 +834,8 @@ static irqreturn_t ironlake_irq_handler(void *arg) done: I915_WRITE(DEIER, de_ier); POSTING_READ(DEIER); + I915_WRITE(SDEIER, sde_ier); + POSTING_READ(SDEIER); } /** @@ -797,20 +847,66 @@ done: */ static void i915_error_work_func(struct work_struct *work) { - drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, - error_work); + struct i915_gpu_error *error = container_of(work, struct i915_gpu_error, + work); + drm_i915_private_t *dev_priv = container_of(error, drm_i915_private_t, + gpu_error); struct drm_device *dev = dev_priv->dev; + struct intel_ring_buffer *ring; +#if 0 + char *error_event[] = { "ERROR=1", NULL }; + char *reset_event[] = { "RESET=1", NULL }; + char *reset_done_event[] = { "ERROR=0", NULL }; +#endif + int i, ret; /* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event); */ - if (atomic_read(&dev_priv->mm.wedged)) { + /* + * Note that there's only one work item which does gpu resets, so we + * need not worry about concurrent gpu resets potentially incrementing + * error->reset_counter twice. We only need to take care of another + * racing irq/hangcheck declaring the gpu dead for a second time. A + * quick check for that is good enough: schedule_work ensures the + * correct ordering between hang detection and this work item, and since + * the reset in-progress bit is only ever set by code outside of this + * work we don't need to worry about any other races. + */ + if (i915_reset_in_progress(error) && !i915_terminally_wedged(error)) { DRM_DEBUG_DRIVER("resetting chip\n"); - /* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event); */ - if (!i915_reset(dev)) { - atomic_set(&dev_priv->mm.wedged, 0); - /* kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event); */ +#if 0 + kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, + reset_event); +#endif + + ret = i915_reset(dev); + + if (ret == 0) { + /* + * After all the gem state is reset, increment the reset + * counter and wake up everyone waiting for the reset to + * complete. + * + * Since unlock operations are a one-sided barrier only, + * we need to insert a barrier here to order any seqno + * updates before + * the counter increment. + */ + cpu_sfence(); + atomic_inc(&dev_priv->gpu_error.reset_counter); + +#if 0 + kobject_uevent_env(&dev->primary->kdev.kobj, + KOBJ_CHANGE, reset_done_event); +#endif + } else { + atomic_set(&error->reset_counter, I915_WEDGED); } - complete_all(&dev_priv->error_completion); + + for_each_ring(ring, dev_priv, i) + wake_up_all(&ring->irq_queue); + + wake_up_all(&dev_priv->gpu_error.reset_queue); } } @@ -873,7 +969,7 @@ i915_error_object_create(struct drm_i915_private *dev_priv, goto unwind; local_irq_save(flags); - if (reloc_offset < dev_priv->mm.gtt_mappable_end && + if (reloc_offset < dev_priv->gtt.mappable_end && src->has_global_gtt_mapping) { void __iomem *s; @@ -882,10 +978,18 @@ i915_error_object_create(struct drm_i915_private *dev_priv, * captures what the GPU read. */ - s = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + s = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, reloc_offset); memcpy_fromio(d, s, PAGE_SIZE); io_mapping_unmap_atomic(s); + } else if (src->stolen) { + unsigned long offset; + + offset = dev_priv->mm.stolen_base; + offset += src->stolen->start; + offset += i << PAGE_SHIFT; + + memcpy_fromio(d, (void *)offset, PAGE_SIZE); } else { struct page *page; void *s; @@ -1033,6 +1137,8 @@ static void i915_gem_record_fences(struct drm_device *dev, error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); break; + default: + BUG(); } } @@ -1181,9 +1287,9 @@ static void i915_capture_error_state(struct drm_device *dev) unsigned long flags; int i, pipe; - spin_lock_irqsave(&dev_priv->error_lock, flags); - error = dev_priv->first_error; - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + error = dev_priv->gpu_error.first_error; + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) return; @@ -1194,7 +1300,8 @@ static void i915_capture_error_state(struct drm_device *dev) return; } - DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n", + DRM_INFO("capturing error event; look for more information in" + "/sys/kernel/debug/dri/%d/i915_error_state\n", dev->primary->index); kref_init(&error->ref); @@ -1277,12 +1384,12 @@ static void i915_capture_error_state(struct drm_device *dev) error->overlay = intel_overlay_capture_error_state(dev); error->display = intel_display_capture_error_state(dev); - spin_lock_irqsave(&dev_priv->error_lock, flags); - if (dev_priv->first_error == NULL) { - dev_priv->first_error = error; + spin_lock_irqsave(&dev_priv->gpu_error.lock, flags); + if (dev_priv->gpu_error.first_error == NULL) { + dev_priv->gpu_error.first_error = error; error = NULL; } - spin_unlock_irqrestore(&dev_priv->error_lock, flags); + spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags); if (error) i915_error_state_free(&error->ref); @@ -1293,10 +1400,10 @@ void i915_destroy_error_state(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_error_state *error; - lockmgr(&dev_priv->error_lock, LK_EXCLUSIVE); - error = dev_priv->first_error; - dev_priv->first_error = NULL; - lockmgr(&dev_priv->error_lock, LK_RELEASE); + lockmgr(&dev_priv->gpu_error.lock, LK_EXCLUSIVE); + error = dev_priv->gpu_error.first_error; + dev_priv->gpu_error.first_error = NULL; + lockmgr(&dev_priv->gpu_error.lock, LK_RELEASE); if (error) i915_error_state_free(dev, error); @@ -1417,17 +1524,18 @@ void i915_handle_error(struct drm_device *dev, bool wedged) i915_report_and_clear_eir(dev); if (wedged) { - INIT_COMPLETION(dev_priv->error_completion); - atomic_set(&dev_priv->mm.wedged, 1); + atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, + &dev_priv->gpu_error.reset_counter); /* - * Wakeup waiting processes so they don't hang + * Wakeup waiting processes so that the reset work item + * doesn't deadlock trying to grab various locks. */ for_each_ring(ring, dev_priv, i) wake_up_all(&ring->irq_queue); } - queue_work(dev_priv->wq, &dev_priv->error_work); + queue_work(dev_priv->wq, &dev_priv->gpu_error.work); } static void i915_pageflip_stall_check(struct drm_device *dev, int pipe) @@ -1653,7 +1761,7 @@ static bool i915_hangcheck_hung(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - if (dev_priv->hangcheck_count++ > 1) { + if (dev_priv->gpu_error.hangcheck_count++ > 1) { bool hung = true; DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); @@ -1712,25 +1820,29 @@ void i915_hangcheck_elapsed(unsigned long data) goto repeat; } - dev_priv->hangcheck_count = 0; + dev_priv->gpu_error.hangcheck_count = 0; return; } i915_get_extra_instdone(dev, instdone); - if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 && - memcmp(dev_priv->prev_instdone, instdone, sizeof(instdone)) == 0) { + if (memcmp(dev_priv->gpu_error.last_acthd, acthd, + sizeof(acthd)) == 0 && + memcmp(dev_priv->gpu_error.prev_instdone, instdone, + sizeof(instdone)) == 0) { if (i915_hangcheck_hung(dev)) return; } else { - dev_priv->hangcheck_count = 0; + dev_priv->gpu_error.hangcheck_count = 0; - memcpy(dev_priv->last_acthd, acthd, sizeof(acthd)); - memcpy(dev_priv->prev_instdone, instdone, sizeof(instdone)); + memcpy(dev_priv->gpu_error.last_acthd, acthd, + sizeof(acthd)); + memcpy(dev_priv->gpu_error.prev_instdone, instdone, + sizeof(instdone)); } repeat: /* Reset timer case chip hangs without another request being added */ - mod_timer(&dev_priv->hangcheck_timer, + mod_timer(&dev_priv->gpu_error.hangcheck_timer, round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES)); } @@ -1800,7 +1912,7 @@ static void valleyview_irq_preinstall(struct drm_device *dev) * This register is the same on all known PCH chips. */ -static void ironlake_enable_pch_hotplug(struct drm_device *dev) +static void ibx_enable_hotplug(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 hotplug; @@ -1813,14 +1925,36 @@ static void ironlake_enable_pch_hotplug(struct drm_device *dev) I915_WRITE(PCH_PORT_HOTPLUG, hotplug); } +static void ibx_irq_postinstall(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 mask; + + if (HAS_PCH_IBX(dev)) + mask = SDE_HOTPLUG_MASK | + SDE_GMBUS | + SDE_AUX_MASK; + else + mask = SDE_HOTPLUG_MASK_CPT | + SDE_GMBUS_CPT | + SDE_AUX_MASK_CPT; + + I915_WRITE(SDEIIR, I915_READ(SDEIIR)); + I915_WRITE(SDEIMR, ~mask); + I915_WRITE(SDEIER, mask); + POSTING_READ(SDEIER); + + ibx_enable_hotplug(dev); +} + static int ironlake_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; /* enable kind of interrupts always enabled */ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT | - DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE; + DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE | + DE_AUX_CHANNEL_A; u32 render_irqs; - u32 hotplug_mask; dev_priv->irq_mask = ~display_mask; @@ -1848,27 +1982,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); - if (HAS_PCH_CPT(dev)) { - hotplug_mask = (SDE_CRT_HOTPLUG_CPT | - SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | - SDE_PORTD_HOTPLUG_CPT); - } else { - hotplug_mask = (SDE_CRT_HOTPLUG | - SDE_PORTB_HOTPLUG | - SDE_PORTC_HOTPLUG | - SDE_PORTD_HOTPLUG | - SDE_AUX_MASK); - } - - dev_priv->pch_irq_mask = ~hotplug_mask; - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); - I915_WRITE(SDEIER, hotplug_mask); - POSTING_READ(SDEIER); - - ironlake_enable_pch_hotplug(dev); + ibx_irq_postinstall(dev); if (IS_IRONLAKE_M(dev)) { /* Clear & enable PCU event interrupts */ @@ -1888,9 +2002,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB | DE_PLANEB_FLIP_DONE_IVB | - DE_PLANEA_FLIP_DONE_IVB; + DE_PLANEA_FLIP_DONE_IVB | + DE_AUX_CHANNEL_A_IVB; u32 render_irqs; - u32 hotplug_mask; dev_priv->irq_mask = ~display_mask; @@ -1914,18 +2028,7 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) I915_WRITE(GTIER, render_irqs); POSTING_READ(GTIER); - hotplug_mask = (SDE_CRT_HOTPLUG_CPT | - SDE_PORTB_HOTPLUG_CPT | - SDE_PORTC_HOTPLUG_CPT | - SDE_PORTD_HOTPLUG_CPT); - dev_priv->pch_irq_mask = ~hotplug_mask; - - I915_WRITE(SDEIIR, I915_READ(SDEIIR)); - I915_WRITE(SDEIMR, dev_priv->pch_irq_mask); - I915_WRITE(SDEIER, hotplug_mask); - POSTING_READ(SDEIER); - - ironlake_enable_pch_hotplug(dev); + ibx_irq_postinstall(dev); return 0; } @@ -1934,7 +2037,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u32 enable_mask; - u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV; u32 render_irqs; u16 msid; @@ -1963,6 +2065,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev) msid |= (1<<14); pci_write_config_word(dev_priv->dev->pdev, 0x98, msid); + I915_WRITE(PORT_HOTPLUG_EN, 0); + POSTING_READ(PORT_HOTPLUG_EN); + I915_WRITE(VLV_IMR, dev_priv->irq_mask); I915_WRITE(VLV_IER, enable_mask); I915_WRITE(VLV_IIR, 0xffffffff); @@ -1971,6 +2076,7 @@ static int valleyview_irq_postinstall(struct drm_device *dev) POSTING_READ(VLV_IER); i915_enable_pipestat(dev_priv, 0, pipestat_enable); + i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); i915_enable_pipestat(dev_priv, 1, pipestat_enable); I915_WRITE(VLV_IIR, 0xffffffff); @@ -1991,13 +2097,22 @@ static int valleyview_irq_postinstall(struct drm_device *dev) #endif I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE); + + return 0; +} + +static void valleyview_hpd_irq_setup(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); + /* Note HDMI and DP share bits */ - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2008,8 +2123,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev) } I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - - return 0; } static void valleyview_irq_uninstall(struct drm_device *dev) @@ -2238,6 +2351,9 @@ static int i915_irq_postinstall(struct drm_device *dev) I915_USER_INTERRUPT; if (I915_HAS_HOTPLUG(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, 0); + POSTING_READ(PORT_HOTPLUG_EN); + /* Enable in IER... */ enable_mask |= I915_DISPLAY_PORT_INTERRUPT; /* and unmask in IMR */ @@ -2248,15 +2364,25 @@ static int i915_irq_postinstall(struct drm_device *dev) I915_WRITE(IER, enable_mask); POSTING_READ(IER); + intel_opregion_enable_asle(dev); + + return 0; +} + +static void i915_hpd_irq_setup(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 hotplug_en; + if (I915_HAS_HOTPLUG(dev)) { - u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); - - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + hotplug_en = I915_READ(PORT_HOTPLUG_EN); + + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_I915) hotplug_en |= SDVOC_HOTPLUG_INT_EN; if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS_I915) @@ -2270,10 +2396,6 @@ static int i915_irq_postinstall(struct drm_device *dev) I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); } - - intel_opregion_enable_asle(dev); - - return 0; } static irqreturn_t i915_irq_handler(void *arg) @@ -2429,7 +2551,6 @@ static void i965_irq_preinstall(struct drm_device * dev) static int i965_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u32 hotplug_en; u32 enable_mask; u32 error_mask; @@ -2450,6 +2571,7 @@ static int i965_irq_postinstall(struct drm_device *dev) dev_priv->pipestat[0] = 0; dev_priv->pipestat[1] = 0; + i915_enable_pipestat(dev_priv, 0, PIPE_GMBUS_EVENT_ENABLE); /* * Enable some error detection, note the instruction error mask @@ -2470,14 +2592,27 @@ static int i965_irq_postinstall(struct drm_device *dev) I915_WRITE(IER, enable_mask); POSTING_READ(IER); + I915_WRITE(PORT_HOTPLUG_EN, 0); + POSTING_READ(PORT_HOTPLUG_EN); + + intel_opregion_enable_asle(dev); + + return 0; +} + +static void i965_hpd_irq_setup(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 hotplug_en; + /* Note HDMI and DP share hotplug bits */ hotplug_en = 0; - if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIB_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS) - hotplug_en |= HDMIC_HOTPLUG_INT_EN; - if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS) - hotplug_en |= HDMID_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTB_HOTPLUG_INT_STATUS) + hotplug_en |= PORTB_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTC_HOTPLUG_INT_STATUS) + hotplug_en |= PORTC_HOTPLUG_INT_EN; + if (dev_priv->hotplug_supported_mask & PORTD_HOTPLUG_INT_STATUS) + hotplug_en |= PORTD_HOTPLUG_INT_EN; if (IS_G4X(dev)) { if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS_G4X) hotplug_en |= SDVOC_HOTPLUG_INT_EN; @@ -2504,10 +2639,6 @@ static int i965_irq_postinstall(struct drm_device *dev) /* Ignore TV since it's buggy */ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); - - intel_opregion_enable_asle(dev); - - return 0; } static irqreturn_t i965_irq_handler(void *arg) @@ -2599,6 +2730,9 @@ static irqreturn_t i965_irq_handler(void *arg) if (blc_event || (iir & I915_ASLE_INTERRUPT)) intel_opregion_asle_intr(dev); + if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS) + gmbus_irq_handler(dev); + /* With MSI, interrupts are only generated when iir * transitions from zero to nonzero. If another bit got * set while we were handling the existing iir bits, then @@ -2648,10 +2782,16 @@ void intel_irq_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->error_work, i915_error_work_func); + INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); + setup_timer(&dev_priv->gpu_error.hangcheck_timer, + i915_hangcheck_elapsed, + (unsigned long) dev); + + pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); + dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { @@ -2672,7 +2812,8 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = valleyview_irq_uninstall; dev->driver->enable_vblank = valleyview_enable_vblank; dev->driver->disable_vblank = valleyview_disable_vblank; - } else if (IS_IVYBRIDGE(dev)) { + dev_priv->display.hpd_irq_setup = valleyview_hpd_irq_setup; + } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) { /* Share pre & uninstall handlers with ILK/SNB */ dev->driver->irq_handler = ivybridge_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2680,14 +2821,6 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_uninstall = ironlake_irq_uninstall; dev->driver->enable_vblank = ivybridge_enable_vblank; dev->driver->disable_vblank = ivybridge_disable_vblank; - } else if (IS_HASWELL(dev)) { - /* Share interrupts handling with IVB */ - dev->driver->irq_handler = ivybridge_irq_handler; - dev->driver->irq_preinstall = ironlake_irq_preinstall; - dev->driver->irq_postinstall = ivybridge_irq_postinstall; - dev->driver->irq_uninstall = ironlake_irq_uninstall; - dev->driver->enable_vblank = ivybridge_enable_vblank; - dev->driver->disable_vblank = ivybridge_disable_vblank; } else if (HAS_PCH_SPLIT(dev)) { dev->driver->irq_handler = ironlake_irq_handler; dev->driver->irq_preinstall = ironlake_irq_preinstall; @@ -2706,13 +2839,23 @@ void intel_irq_init(struct drm_device *dev) dev->driver->irq_postinstall = i915_irq_postinstall; dev->driver->irq_uninstall = i915_irq_uninstall; dev->driver->irq_handler = i915_irq_handler; + dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup; } else { dev->driver->irq_preinstall = i965_irq_preinstall; dev->driver->irq_postinstall = i965_irq_postinstall; dev->driver->irq_uninstall = i965_irq_uninstall; dev->driver->irq_handler = i965_irq_handler; + dev_priv->display.hpd_irq_setup = i965_hpd_irq_setup; } dev->driver->enable_vblank = i915_enable_vblank; dev->driver->disable_vblank = i915_disable_vblank; } } + +void intel_hpd_init(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); +} diff --git a/sys/dev/drm/i915/i915_reg.h b/sys/dev/drm/i915/i915_reg.h index ce70f0ac1c..c91124f925 100644 --- a/sys/dev/drm/i915/i915_reg.h +++ b/sys/dev/drm/i915/i915_reg.h @@ -141,8 +141,15 @@ #define VGA_MSR_MEM_EN (1<<1) #define VGA_MSR_CGA_MODE (1<<0) -#define VGA_SR_INDEX 0x3c4 -#define VGA_SR_DATA 0x3c5 +/* + * SR01 is the only VGA register touched on non-UMS setups. + * VLV doesn't do UMS, so the sequencer index/data registers + * are the only VGA registers which need to include + * display_mmio_offset. + */ +#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4) +#define SR01 1 +#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5) #define VGA_AR_INDEX 0x3c0 #define VGA_AR_VID_EN (1<<5) @@ -301,6 +308,7 @@ #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) +#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ #define PIPE_CONTROL_CS_STALL (1<<20) #define PIPE_CONTROL_TLB_INVALIDATE (1<<18) #define PIPE_CONTROL_QW_WRITE (1<<14) @@ -335,17 +343,19 @@ * 0x801c/3c: core clock bits * 0x8048/68: low pass filter coefficients * 0x8100: fast clock controls + * + * DPIO is VLV only. */ -#define DPIO_PKT 0x2100 +#define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100) #define DPIO_RID (0<<24) #define DPIO_OP_WRITE (1<<16) #define DPIO_OP_READ (0<<16) #define DPIO_PORTID (0x12<<8) #define DPIO_BYTE (0xf<<4) #define DPIO_BUSY (1<<0) /* status only */ -#define DPIO_DATA 0x2104 -#define DPIO_REG 0x2108 -#define DPIO_CTL 0x2110 +#define DPIO_DATA (VLV_DISPLAY_BASE + 0x2104) +#define DPIO_REG (VLV_DISPLAY_BASE + 0x2108) +#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110) #define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ #define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ #define DPIO_SFR_BYPASS (1<<1) @@ -556,13 +566,13 @@ #define IIR 0x020a4 #define IMR 0x020a8 #define ISR 0x020ac -#define VLV_GUNIT_CLOCK_GATE 0x182060 +#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) #define GCFG_DIS (1<<8) -#define VLV_IIR_RW 0x182084 -#define VLV_IER 0x1820a0 -#define VLV_IIR 0x1820a4 -#define VLV_IMR 0x1820a8 -#define VLV_ISR 0x1820ac +#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) +#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) +#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) +#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) +#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) #define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18) #define I915_DISPLAY_PORT_INTERRUPT (1<<17) #define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15) @@ -735,6 +745,7 @@ #define GEN7_FF_TS_SCHED_HS0 (0x3<<16) #define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) #define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */ +#define GEN7_FF_VS_REF_CNT_FFME (1 << 15) #define GEN7_FF_VS_SCHED_HS1 (0x5<<12) #define GEN7_FF_VS_SCHED_HS0 (0x3<<12) #define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */ @@ -921,8 +932,8 @@ #define VGA1_PD_P1_DIV_2 (1 << 13) #define VGA1_PD_P1_SHIFT 8 #define VGA1_PD_P1_MASK (0x1f << 8) -#define _DPLL_A 0x06014 -#define _DPLL_B 0x06018 +#define _DPLL_A (dev_priv->info->display_mmio_offset + 0x6014) +#define _DPLL_B (dev_priv->info->display_mmio_offset + 0x6018) #define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B) #define DPLL_VCO_ENABLE (1 << 31) #define DPLL_DVO_HIGH_SPEED (1 << 30) @@ -943,23 +954,6 @@ #define DPLL_LOCK_VLV (1<<15) #define DPLL_INTEGRATED_CLOCK_VLV (1<<13) -#define SRX_INDEX 0x3c4 -#define SRX_DATA 0x3c5 -#define SR01 1 -#define SR01_SCREEN_OFF (1<<5) - -#define PPCR 0x61204 -#define PPCR_ON (1<<0) - -#define DVOB 0x61140 -#define DVOB_ON (1<<31) -#define DVOC 0x61160 -#define DVOC_ON (1<<31) -#define LVDS 0x61180 -#define LVDS_ON (1<<31) - -/* Scratch pad debug 0 reg: - */ #define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 /* * The i830 generation, in LVDS mode, defines P1 as the bit number set within @@ -998,7 +992,7 @@ #define SDVO_MULTIPLIER_MASK 0x000000ff #define SDVO_MULTIPLIER_SHIFT_HIRES 4 #define SDVO_MULTIPLIER_SHIFT_VGA 0 -#define _DPLL_A_MD 0x0601c /* 965+ only */ +#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */ /* * UDI pixel divider, controlling how many pixels are stuffed into a packet. * @@ -1035,7 +1029,7 @@ */ #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -#define _DPLL_B_MD 0x06020 /* 965+ only */ +#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */ #define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD) #define _FPA0 0x06040 @@ -1178,15 +1172,15 @@ #define RAMCLK_GATE_D 0x6210 /* CRL only */ #define DEUC 0x6214 /* CRL only */ -#define FW_BLC_SELF_VLV 0x6500 +#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500) #define FW_CSPWRDWNEN (1<<15) /* * Palette regs */ -#define _PALETTE_A 0x0a000 -#define _PALETTE_B 0x0a800 +#define _PALETTE_A (dev_priv->info->display_mmio_offset + 0xa000) +#define _PALETTE_B (dev_priv->info->display_mmio_offset + 0xa800) #define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B) /* MCH MMIO space */ @@ -1242,6 +1236,10 @@ #define MAD_DIMM_A_SIZE_SHIFT 0 #define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) +/** snb MCH registers for priority tuning */ +#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10) +#define MCH_SSKPD_WM0_MASK 0x3f +#define MCH_SSKPD_WM0_VAL 0xc /* Clocking configuration register */ #define CLKCFG 0x10c00 @@ -1551,26 +1549,26 @@ */ /* Pipe A timing regs */ -#define _HTOTAL_A 0x60000 -#define _HBLANK_A 0x60004 -#define _HSYNC_A 0x60008 -#define _VTOTAL_A 0x6000c -#define _VBLANK_A 0x60010 -#define _VSYNC_A 0x60014 -#define _PIPEASRC 0x6001c -#define _BCLRPAT_A 0x60020 -#define _VSYNCSHIFT_A 0x60028 +#define _HTOTAL_A (dev_priv->info->display_mmio_offset + 0x60000) +#define _HBLANK_A (dev_priv->info->display_mmio_offset + 0x60004) +#define _HSYNC_A (dev_priv->info->display_mmio_offset + 0x60008) +#define _VTOTAL_A (dev_priv->info->display_mmio_offset + 0x6000c) +#define _VBLANK_A (dev_priv->info->display_mmio_offset + 0x60010) +#define _VSYNC_A (dev_priv->info->display_mmio_offset + 0x60014) +#define _PIPEASRC (dev_priv->info->display_mmio_offset + 0x6001c) +#define _BCLRPAT_A (dev_priv->info->display_mmio_offset + 0x60020) +#define _VSYNCSHIFT_A (dev_priv->info->display_mmio_offset + 0x60028) /* Pipe B timing regs */ -#define _HTOTAL_B 0x61000 -#define _HBLANK_B 0x61004 -#define _HSYNC_B 0x61008 -#define _VTOTAL_B 0x6100c -#define _VBLANK_B 0x61010 -#define _VSYNC_B 0x61014 -#define _PIPEBSRC 0x6101c -#define _BCLRPAT_B 0x61020 -#define _VSYNCSHIFT_B 0x61028 +#define _HTOTAL_B (dev_priv->info->display_mmio_offset + 0x61000) +#define _HBLANK_B (dev_priv->info->display_mmio_offset + 0x61004) +#define _HSYNC_B (dev_priv->info->display_mmio_offset + 0x61008) +#define _VTOTAL_B (dev_priv->info->display_mmio_offset + 0x6100c) +#define _VBLANK_B (dev_priv->info->display_mmio_offset + 0x61010) +#define _VSYNC_B (dev_priv->info->display_mmio_offset + 0x61014) +#define _PIPEBSRC (dev_priv->info->display_mmio_offset + 0x6101c) +#define _BCLRPAT_B (dev_priv->info->display_mmio_offset + 0x61020) +#define _VSYNCSHIFT_B (dev_priv->info->display_mmio_offset + 0x61028) #define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B) @@ -1615,9 +1613,9 @@ #define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) #define ADPA_USE_VGA_HVPOLARITY (1<<15) #define ADPA_SETS_HVPOLARITY 0 -#define ADPA_VSYNC_CNTL_DISABLE (1<<11) +#define ADPA_VSYNC_CNTL_DISABLE (1<<10) #define ADPA_VSYNC_CNTL_ENABLE 0 -#define ADPA_HSYNC_CNTL_DISABLE (1<<10) +#define ADPA_HSYNC_CNTL_DISABLE (1<<11) #define ADPA_HSYNC_CNTL_ENABLE 0 #define ADPA_VSYNC_ACTIVE_HIGH (1<<4) #define ADPA_VSYNC_ACTIVE_LOW 0 @@ -1631,13 +1629,10 @@ /* Hotplug control (945+ only) */ -#define PORT_HOTPLUG_EN 0x61110 -#define HDMIB_HOTPLUG_INT_EN (1 << 29) -#define DPB_HOTPLUG_INT_EN (1 << 29) -#define HDMIC_HOTPLUG_INT_EN (1 << 28) -#define DPC_HOTPLUG_INT_EN (1 << 28) -#define HDMID_HOTPLUG_INT_EN (1 << 27) -#define DPD_HOTPLUG_INT_EN (1 << 27) +#define PORT_HOTPLUG_EN (dev_priv->info->display_mmio_offset + 0x61110) +#define PORTB_HOTPLUG_INT_EN (1 << 29) +#define PORTC_HOTPLUG_INT_EN (1 << 28) +#define PORTD_HOTPLUG_INT_EN (1 << 27) #define SDVOB_HOTPLUG_INT_EN (1 << 26) #define SDVOC_HOTPLUG_INT_EN (1 << 25) #define TV_HOTPLUG_INT_EN (1 << 18) @@ -1658,21 +1653,14 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) -#define PORT_HOTPLUG_STAT 0x61114 +#define PORT_HOTPLUG_STAT (dev_priv->info->display_mmio_offset + 0x61114) /* HDMI/DP bits are gen4+ */ -#define DPB_HOTPLUG_LIVE_STATUS (1 << 29) -#define DPC_HOTPLUG_LIVE_STATUS (1 << 28) -#define DPD_HOTPLUG_LIVE_STATUS (1 << 27) -#define DPD_HOTPLUG_INT_STATUS (3 << 21) -#define DPC_HOTPLUG_INT_STATUS (3 << 19) -#define DPB_HOTPLUG_INT_STATUS (3 << 17) -/* HDMI bits are shared with the DP bits */ -#define HDMIB_HOTPLUG_LIVE_STATUS (1 << 29) -#define HDMIC_HOTPLUG_LIVE_STATUS (1 << 28) -#define HDMID_HOTPLUG_LIVE_STATUS (1 << 27) -#define HDMID_HOTPLUG_INT_STATUS (3 << 21) -#define HDMIC_HOTPLUG_INT_STATUS (3 << 19) -#define HDMIB_HOTPLUG_INT_STATUS (3 << 17) +#define PORTB_HOTPLUG_LIVE_STATUS (1 << 29) +#define PORTC_HOTPLUG_LIVE_STATUS (1 << 28) +#define PORTD_HOTPLUG_LIVE_STATUS (1 << 27) +#define PORTD_HOTPLUG_INT_STATUS (3 << 21) +#define PORTC_HOTPLUG_INT_STATUS (3 << 19) +#define PORTB_HOTPLUG_INT_STATUS (3 << 17) /* CRT/TV common between gen3+ */ #define CRT_HOTPLUG_INT_STATUS (1 << 11) #define TV_HOTPLUG_INT_STATUS (1 << 10) @@ -1877,7 +1865,7 @@ #define PP_DIVISOR 0x61210 /* Panel fitting */ -#define PFIT_CONTROL 0x61230 +#define PFIT_CONTROL (dev_priv->info->display_mmio_offset + 0x61230) #define PFIT_ENABLE (1 << 31) #define PFIT_PIPE_MASK (3 << 29) #define PFIT_PIPE_SHIFT 29 @@ -1895,9 +1883,7 @@ #define PFIT_SCALING_PROGRAMMED (1 << 26) #define PFIT_SCALING_PILLAR (2 << 26) #define PFIT_SCALING_LETTER (3 << 26) -#define PFIT_PGM_RATIOS 0x61234 -#define PFIT_VERT_SCALE_MASK 0xfff00000 -#define PFIT_HORIZ_SCALE_MASK 0x0000fff0 +#define PFIT_PGM_RATIOS (dev_priv->info->display_mmio_offset + 0x61234) /* Pre-965 */ #define PFIT_VERT_SCALE_SHIFT 20 #define PFIT_VERT_SCALE_MASK 0xfff00000 @@ -1909,7 +1895,7 @@ #define PFIT_HORIZ_SCALE_SHIFT_965 0 #define PFIT_HORIZ_SCALE_MASK_965 0x00001fff -#define PFIT_AUTO_RATIOS 0x61238 +#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238) /* Backlight control */ #define BLC_PWM_CTL2 0x61250 /* 965+ only */ @@ -2639,10 +2625,10 @@ /* Display & cursor control */ /* Pipe A */ -#define _PIPEADSL 0x70000 +#define _PIPEADSL (dev_priv->info->display_mmio_offset + 0x70000) #define DSL_LINEMASK_GEN2 0x00000fff #define DSL_LINEMASK_GEN3 0x00001fff -#define _PIPEACONF 0x70008 +#define _PIPEACONF (dev_priv->info->display_mmio_offset + 0x70008) #define PIPECONF_ENABLE (1<<31) #define PIPECONF_DISABLE 0 #define PIPECONF_DOUBLE_WIDE (1<<30) @@ -2671,18 +2657,19 @@ #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ #define PIPECONF_CXSR_DOWNCLOCK (1<<16) -#define PIPECONF_BPP_MASK (0x000000e0) -#define PIPECONF_BPP_8 (0<<5) -#define PIPECONF_BPP_10 (1<<5) -#define PIPECONF_BPP_6 (2<<5) -#define PIPECONF_BPP_12 (3<<5) +#define PIPECONF_COLOR_RANGE_SELECT (1 << 13) +#define PIPECONF_BPC_MASK (0x7 << 5) +#define PIPECONF_8BPC (0<<5) +#define PIPECONF_10BPC (1<<5) +#define PIPECONF_6BPC (2<<5) +#define PIPECONF_12BPC (3<<5) #define PIPECONF_DITHER_EN (1<<4) #define PIPECONF_DITHER_TYPE_MASK (0x0000000c) #define PIPECONF_DITHER_TYPE_SP (0<<2) #define PIPECONF_DITHER_TYPE_ST1 (1<<2) #define PIPECONF_DITHER_TYPE_ST2 (2<<2) #define PIPECONF_DITHER_TYPE_TEMP (3<<2) -#define _PIPEASTAT 0x70024 +#define _PIPEASTAT (dev_priv->info->display_mmio_offset + 0x70024) #define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31) #define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30) #define PIPE_CRC_ERROR_ENABLE (1UL<<29) @@ -2693,7 +2680,7 @@ #define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25) #define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) #define PIPE_DPST_EVENT_ENABLE (1UL<<23) -#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<26) +#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<22) #define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22) #define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) #define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) @@ -2703,7 +2690,7 @@ #define PIPEA_HBLANK_INT_EN_VLV (1UL<<16) #define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16) #define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15) -#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<15) +#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<14) #define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) #define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12) #define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11) @@ -2719,11 +2706,6 @@ #define PIPE_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ #define PIPE_VBLANK_INTERRUPT_STATUS (1UL<<1) #define PIPE_OVERLAY_UPDATED_STATUS (1UL<<0) -#define PIPE_BPC_MASK (7 << 5) /* Ironlake */ -#define PIPE_8BPC (0 << 5) -#define PIPE_10BPC (1 << 5) -#define PIPE_6BPC (2 << 5) -#define PIPE_12BPC (3 << 5) #define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC) #define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF) @@ -2732,7 +2714,7 @@ #define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL) #define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT) -#define VLV_DPFLIPSTAT 0x70028 +#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028) #define PIPEB_LINE_COMPARE_INT_EN (1<<29) #define PIPEB_HLINE_INT_EN (1<<28) #define PIPEB_VBLANK_INT_EN (1<<27) @@ -2746,7 +2728,7 @@ #define SPRITEA_FLIPDONE_INT_EN (1<<17) #define PLANEA_FLIPDONE_INT_EN (1<<16) -#define DPINVGTT 0x7002c /* VLV only */ +#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */ #define CURSORB_INVALID_GTT_INT_EN (1<<23) #define CURSORA_INVALID_GTT_INT_EN (1<<22) #define SPRITED_INVALID_GTT_INT_EN (1<<21) @@ -2774,7 +2756,7 @@ #define DSPARB_BEND_SHIFT 9 /* on 855 */ #define DSPARB_AEND_SHIFT 0 -#define DSPFW1 0x70034 +#define DSPFW1 (dev_priv->info->display_mmio_offset + 0x70034) #define DSPFW_SR_SHIFT 23 #define DSPFW_SR_MASK (0x1ff<<23) #define DSPFW_CURSORB_SHIFT 16 @@ -2782,11 +2764,11 @@ #define DSPFW_PLANEB_SHIFT 8 #define DSPFW_PLANEB_MASK (0x7f<<8) #define DSPFW_PLANEA_MASK (0x7f) -#define DSPFW2 0x70038 +#define DSPFW2 (dev_priv->info->display_mmio_offset + 0x70038) #define DSPFW_CURSORA_MASK 0x00003f00 #define DSPFW_CURSORA_SHIFT 8 #define DSPFW_PLANEC_MASK (0x7f) -#define DSPFW3 0x7003c +#define DSPFW3 (dev_priv->info->display_mmio_offset + 0x7003c) #define DSPFW_HPLL_SR_EN (1<<31) #define DSPFW_CURSOR_SR_SHIFT 24 #define PINEVIEW_SELF_REFRESH_EN (1<<30) @@ -2798,13 +2780,13 @@ /* drain latency register values*/ #define DRAIN_LATENCY_PRECISION_32 32 #define DRAIN_LATENCY_PRECISION_16 16 -#define VLV_DDL1 0x70050 +#define VLV_DDL1 (VLV_DISPLAY_BASE + 0x70050) #define DDL_CURSORA_PRECISION_32 (1<<31) #define DDL_CURSORA_PRECISION_16 (0<<31) #define DDL_CURSORA_SHIFT 24 #define DDL_PLANEA_PRECISION_32 (1<<7) #define DDL_PLANEA_PRECISION_16 (0<<7) -#define VLV_DDL2 0x70054 +#define VLV_DDL2 (VLV_DISPLAY_BASE + 0x70054) #define DDL_CURSORB_PRECISION_32 (1<<31) #define DDL_CURSORB_PRECISION_16 (0<<31) #define DDL_CURSORB_SHIFT 24 @@ -2948,10 +2930,10 @@ * } while (high1 != high2); * frame = (high1 << 8) | low1; */ -#define _PIPEAFRAMEHIGH 0x70040 +#define _PIPEAFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x70040) #define PIPE_FRAME_HIGH_MASK 0x0000ffff #define PIPE_FRAME_HIGH_SHIFT 0 -#define _PIPEAFRAMEPIXEL 0x70044 +#define _PIPEAFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x70044) #define PIPE_FRAME_LOW_MASK 0xff000000 #define PIPE_FRAME_LOW_SHIFT 24 #define PIPE_PIXEL_MASK 0x00ffffff @@ -2962,11 +2944,12 @@ #define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45) /* Cursor A & B regs */ -#define _CURACNTR 0x70080 +#define _CURACNTR (dev_priv->info->display_mmio_offset + 0x70080) /* Old style CUR*CNTR flags (desktop 8xx) */ #define CURSOR_ENABLE 0x80000000 #define CURSOR_GAMMA_ENABLE 0x40000000 #define CURSOR_STRIDE_MASK 0x30000000 +#define CURSOR_PIPE_CSC_ENABLE (1<<24) #define CURSOR_FORMAT_SHIFT 24 #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) @@ -2983,16 +2966,16 @@ #define MCURSOR_PIPE_A 0x00 #define MCURSOR_PIPE_B (1 << 28) #define MCURSOR_GAMMA_ENABLE (1 << 26) -#define _CURABASE 0x70084 -#define _CURAPOS 0x70088 +#define _CURABASE (dev_priv->info->display_mmio_offset + 0x70084) +#define _CURAPOS (dev_priv->info->display_mmio_offset + 0x70088) #define CURSOR_POS_MASK 0x007FF #define CURSOR_POS_SIGN 0x8000 #define CURSOR_X_SHIFT 0 #define CURSOR_Y_SHIFT 16 #define CURSIZE 0x700a0 -#define _CURBCNTR 0x700c0 -#define _CURBBASE 0x700c4 -#define _CURBPOS 0x700c8 +#define _CURBCNTR (dev_priv->info->display_mmio_offset + 0x700c0) +#define _CURBBASE (dev_priv->info->display_mmio_offset + 0x700c4) +#define _CURBPOS (dev_priv->info->display_mmio_offset + 0x700c8) #define _CURBCNTR_IVB 0x71080 #define _CURBBASE_IVB 0x71084 @@ -3007,7 +2990,7 @@ #define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB) /* Display A control */ -#define _DSPACNTR 0x70180 +#define _DSPACNTR (dev_priv->info->display_mmio_offset + 0x70180) #define DISPLAY_PLANE_ENABLE (1<<31) #define DISPLAY_PLANE_DISABLE 0 #define DISPPLANE_GAMMA_ENABLE (1<<30) @@ -3028,6 +3011,7 @@ #define DISPPLANE_RGBA888 (0xf<<26) #define DISPPLANE_STEREO_ENABLE (1<<25) #define DISPPLANE_STEREO_DISABLE 0 +#define DISPPLANE_PIPE_CSC_ENABLE (1<<24) #define DISPPLANE_SEL_PIPE_SHIFT 24 #define DISPPLANE_SEL_PIPE_MASK (3<info->display_mmio_offset + 0x70184) +#define _DSPASTRIDE (dev_priv->info->display_mmio_offset + 0x70188) +#define _DSPAPOS (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */ +#define _DSPASIZE (dev_priv->info->display_mmio_offset + 0x70190) +#define _DSPASURF (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */ +#define _DSPATILEOFF (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */ +#define _DSPAOFFSET (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */ +#define _DSPASURFLIVE (dev_priv->info->display_mmio_offset + 0x701AC) #define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR) #define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR) @@ -3068,44 +3052,44 @@ (I915_WRITE((reg), (gfx_addr) | I915_LO_DISPBASE(I915_READ(reg)))) /* VBIOS flags */ -#define SWF00 0x71410 -#define SWF01 0x71414 -#define SWF02 0x71418 -#define SWF03 0x7141c -#define SWF04 0x71420 -#define SWF05 0x71424 -#define SWF06 0x71428 -#define SWF10 0x70410 -#define SWF11 0x70414 -#define SWF14 0x71420 -#define SWF30 0x72414 -#define SWF31 0x72418 -#define SWF32 0x7241c +#define SWF00 (dev_priv->info->display_mmio_offset + 0x71410) +#define SWF01 (dev_priv->info->display_mmio_offset + 0x71414) +#define SWF02 (dev_priv->info->display_mmio_offset + 0x71418) +#define SWF03 (dev_priv->info->display_mmio_offset + 0x7141c) +#define SWF04 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF05 (dev_priv->info->display_mmio_offset + 0x71424) +#define SWF06 (dev_priv->info->display_mmio_offset + 0x71428) +#define SWF10 (dev_priv->info->display_mmio_offset + 0x70410) +#define SWF11 (dev_priv->info->display_mmio_offset + 0x70414) +#define SWF14 (dev_priv->info->display_mmio_offset + 0x71420) +#define SWF30 (dev_priv->info->display_mmio_offset + 0x72414) +#define SWF31 (dev_priv->info->display_mmio_offset + 0x72418) +#define SWF32 (dev_priv->info->display_mmio_offset + 0x7241c) /* Pipe B */ -#define _PIPEBDSL 0x71000 -#define _PIPEBCONF 0x71008 -#define _PIPEBSTAT 0x71024 -#define _PIPEBFRAMEHIGH 0x71040 -#define _PIPEBFRAMEPIXEL 0x71044 +#define _PIPEBDSL (dev_priv->info->display_mmio_offset + 0x71000) +#define _PIPEBCONF (dev_priv->info->display_mmio_offset + 0x71008) +#define _PIPEBSTAT (dev_priv->info->display_mmio_offset + 0x71024) +#define _PIPEBFRAMEHIGH (dev_priv->info->display_mmio_offset + 0x71040) +#define _PIPEBFRAMEPIXEL (dev_priv->info->display_mmio_offset + 0x71044) #define _PIPEB_FRMCOUNT_GM45 0x71040 #define _PIPEB_FLIPCOUNT_GM45 0x71044 /* Display B control */ -#define _DSPBCNTR 0x71180 +#define _DSPBCNTR (dev_priv->info->display_mmio_offset + 0x71180) #define DISPPLANE_ALPHA_TRANS_ENABLE (1<<15) #define DISPPLANE_ALPHA_TRANS_DISABLE 0 #define DISPPLANE_SPRITE_ABOVE_DISPLAY 0 #define DISPPLANE_SPRITE_ABOVE_OVERLAY (1) -#define _DSPBADDR 0x71184 -#define _DSPBSTRIDE 0x71188 -#define _DSPBPOS 0x7118C -#define _DSPBSIZE 0x71190 -#define _DSPBSURF 0x7119C -#define _DSPBTILEOFF 0x711A4 -#define _DSPBOFFSET 0x711A4 -#define _DSPBSURFLIVE 0x711AC +#define _DSPBADDR (dev_priv->info->display_mmio_offset + 0x71184) +#define _DSPBSTRIDE (dev_priv->info->display_mmio_offset + 0x71188) +#define _DSPBPOS (dev_priv->info->display_mmio_offset + 0x7118C) +#define _DSPBSIZE (dev_priv->info->display_mmio_offset + 0x71190) +#define _DSPBSURF (dev_priv->info->display_mmio_offset + 0x7119C) +#define _DSPBTILEOFF (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBOFFSET (dev_priv->info->display_mmio_offset + 0x711A4) +#define _DSPBSURFLIVE (dev_priv->info->display_mmio_offset + 0x711AC) /* Sprite A control */ #define _DVSACNTR 0x72180 @@ -3116,6 +3100,7 @@ #define DVS_FORMAT_RGBX101010 (1<<25) #define DVS_FORMAT_RGBX888 (2<<25) #define DVS_FORMAT_RGBX161616 (3<<25) +#define DVS_PIPE_CSC_ENABLE (1<<24) #define DVS_SOURCE_KEY (1<<22) #define DVS_RGB_ORDER_XBGR (1<<20) #define DVS_YUV_BYTE_ORDER_MASK (3<<16) @@ -3183,7 +3168,7 @@ #define SPRITE_FORMAT_RGBX161616 (3<<25) #define SPRITE_FORMAT_YUV444 (4<<25) #define SPRITE_FORMAT_XR_BGR101010 (5<<25) /* Extended range */ -#define SPRITE_CSC_ENABLE (1<<24) +#define SPRITE_PIPE_CSC_ENABLE (1<<24) #define SPRITE_SOURCE_KEY (1<<22) #define SPRITE_RGB_ORDER_RGBX (1<<20) /* only for 888 and 161616 */ #define SPRITE_YUV_TO_RGB_CSC_DISABLE (1<<19) @@ -3254,6 +3239,8 @@ # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) +#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400) + /* Ironlake */ #define CPU_VGACNTRL 0x41000 @@ -3294,41 +3281,41 @@ #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff -#define _PIPEA_DATA_M1 0x60030 +#define _PIPEA_DATA_M1 (dev_priv->info->display_mmio_offset + 0x60030) #define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */ #define TU_SIZE_MASK 0x7e000000 #define PIPE_DATA_M1_OFFSET 0 -#define _PIPEA_DATA_N1 0x60034 +#define _PIPEA_DATA_N1 (dev_priv->info->display_mmio_offset + 0x60034) #define PIPE_DATA_N1_OFFSET 0 -#define _PIPEA_DATA_M2 0x60038 +#define _PIPEA_DATA_M2 (dev_priv->info->display_mmio_offset + 0x60038) #define PIPE_DATA_M2_OFFSET 0 -#define _PIPEA_DATA_N2 0x6003c +#define _PIPEA_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6003c) #define PIPE_DATA_N2_OFFSET 0 -#define _PIPEA_LINK_M1 0x60040 +#define _PIPEA_LINK_M1 (dev_priv->info->display_mmio_offset + 0x60040) #define PIPE_LINK_M1_OFFSET 0 -#define _PIPEA_LINK_N1 0x60044 +#define _PIPEA_LINK_N1 (dev_priv->info->display_mmio_offset + 0x60044) #define PIPE_LINK_N1_OFFSET 0 -#define _PIPEA_LINK_M2 0x60048 +#define _PIPEA_LINK_M2 (dev_priv->info->display_mmio_offset + 0x60048) #define PIPE_LINK_M2_OFFSET 0 -#define _PIPEA_LINK_N2 0x6004c +#define _PIPEA_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6004c) #define PIPE_LINK_N2_OFFSET 0 /* PIPEB timing regs are same start from 0x61000 */ -#define _PIPEB_DATA_M1 0x61030 -#define _PIPEB_DATA_N1 0x61034 +#define _PIPEB_DATA_M1 (dev_priv->info->display_mmio_offset + 0x61030) +#define _PIPEB_DATA_N1 (dev_priv->info->display_mmio_offset + 0x61034) -#define _PIPEB_DATA_M2 0x61038 -#define _PIPEB_DATA_N2 0x6103c +#define _PIPEB_DATA_M2 (dev_priv->info->display_mmio_offset + 0x61038) +#define _PIPEB_DATA_N2 (dev_priv->info->display_mmio_offset + 0x6103c) -#define _PIPEB_LINK_M1 0x61040 -#define _PIPEB_LINK_N1 0x61044 +#define _PIPEB_LINK_M1 (dev_priv->info->display_mmio_offset + 0x61040) +#define _PIPEB_LINK_N1 (dev_priv->info->display_mmio_offset + 0x61044) -#define _PIPEB_LINK_M2 0x61048 -#define _PIPEB_LINK_N2 0x6104c +#define _PIPEB_LINK_M2 (dev_priv->info->display_mmio_offset + 0x61048) +#define _PIPEB_LINK_N2 (dev_priv->info->display_mmio_offset + 0x6104c) #define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1) #define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1) @@ -3581,27 +3568,30 @@ #define PORTD_PULSE_DURATION_6ms (2 << 18) #define PORTD_PULSE_DURATION_100ms (3 << 18) #define PORTD_PULSE_DURATION_MASK (3 << 18) -#define PORTD_HOTPLUG_NO_DETECT (0) -#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) -#define PORTD_HOTPLUG_LONG_DETECT (1 << 17) +#define PORTD_HOTPLUG_STATUS_MASK (0x3 << 16) +#define PORTD_HOTPLUG_NO_DETECT (0 << 16) +#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) +#define PORTD_HOTPLUG_LONG_DETECT (2 << 16) #define PORTC_HOTPLUG_ENABLE (1 << 12) #define PORTC_PULSE_DURATION_2ms (0) #define PORTC_PULSE_DURATION_4_5ms (1 << 10) #define PORTC_PULSE_DURATION_6ms (2 << 10) #define PORTC_PULSE_DURATION_100ms (3 << 10) #define PORTC_PULSE_DURATION_MASK (3 << 10) -#define PORTC_HOTPLUG_NO_DETECT (0) -#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) -#define PORTC_HOTPLUG_LONG_DETECT (1 << 9) +#define PORTC_HOTPLUG_STATUS_MASK (0x3 << 8) +#define PORTC_HOTPLUG_NO_DETECT (0 << 8) +#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) +#define PORTC_HOTPLUG_LONG_DETECT (2 << 8) #define PORTB_HOTPLUG_ENABLE (1 << 4) #define PORTB_PULSE_DURATION_2ms (0) #define PORTB_PULSE_DURATION_4_5ms (1 << 2) #define PORTB_PULSE_DURATION_6ms (2 << 2) #define PORTB_PULSE_DURATION_100ms (3 << 2) #define PORTB_PULSE_DURATION_MASK (3 << 2) -#define PORTB_HOTPLUG_NO_DETECT (0) -#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) -#define PORTB_HOTPLUG_LONG_DETECT (1 << 1) +#define PORTB_HOTPLUG_STATUS_MASK (0x3 << 0) +#define PORTB_HOTPLUG_NO_DETECT (0 << 0) +#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) +#define PORTB_HOTPLUG_LONG_DETECT (2 << 0) #define PCH_GPIOA 0xc5010 #define PCH_GPIOB 0xc5014 @@ -3722,13 +3712,13 @@ #define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) #define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) -#define VLV_VIDEO_DIP_CTL_A 0x60200 -#define VLV_VIDEO_DIP_DATA_A 0x60208 -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210 +#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200) +#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210) -#define VLV_VIDEO_DIP_CTL_B 0x61170 -#define VLV_VIDEO_DIP_DATA_B 0x61174 -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B 0x61178 +#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170) +#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174) +#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178) #define VLV_TVIDEO_DIP_CTL(pipe) \ _PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B) @@ -3820,8 +3810,6 @@ #define TRANS_FSYNC_DELAY_HB2 (1<<27) #define TRANS_FSYNC_DELAY_HB3 (2<<27) #define TRANS_FSYNC_DELAY_HB4 (3<<27) -#define TRANS_DP_AUDIO_ONLY (1<<26) -#define TRANS_DP_VIDEO_AUDIO (0<<26) #define TRANS_INTERLACE_MASK (7<<21) #define TRANS_PROGRESSIVE (0<<21) #define TRANS_INTERLACED (3<<21) @@ -4020,17 +4008,17 @@ #define LVDS_DETECTED (1 << 1) /* vlv has 2 sets of panel control regs. */ -#define PIPEA_PP_STATUS 0x61200 -#define PIPEA_PP_CONTROL 0x61204 -#define PIPEA_PP_ON_DELAYS 0x61208 -#define PIPEA_PP_OFF_DELAYS 0x6120c -#define PIPEA_PP_DIVISOR 0x61210 - -#define PIPEB_PP_STATUS 0x61300 -#define PIPEB_PP_CONTROL 0x61304 -#define PIPEB_PP_ON_DELAYS 0x61308 -#define PIPEB_PP_OFF_DELAYS 0x6130c -#define PIPEB_PP_DIVISOR 0x61310 +#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200) +#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204) +#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208) +#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c) +#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210) + +#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300) +#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304) +#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308) +#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) +#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) #define PCH_PP_STATUS 0xc7200 #define PCH_PP_CONTROL 0xc7204 @@ -4324,7 +4312,7 @@ #define GEN7_ROW_CHICKEN2_GT2 0xf4f4 #define DOP_CLOCK_GATING_DISABLE (1<<0) -#define G4X_AUD_VID_DID 0x62020 +#define G4X_AUD_VID_DID (dev_priv->info->display_mmio_offset + 0x62020) #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 #define INTEL_AUDIO_DEVCTG 0x80862802 @@ -4440,10 +4428,10 @@ #define AUDIO_CP_READY_C (1<<9) /* HSW Power Wells */ -#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */ -#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */ -#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */ -#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */ +#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ +#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */ +#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */ +#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */ #define HSW_PWR_WELL_ENABLE (1<<31) #define HSW_PWR_WELL_STATE (1<<30) #define HSW_PWR_WELL_CTL5 0x45410 @@ -4660,4 +4648,51 @@ #define WM_DBG_DISALLOW_MAXFIFO (1<<1) #define WM_DBG_DISALLOW_SPRITE (1<<2) +/* pipe CSC */ +#define _PIPE_A_CSC_COEFF_RY_GY 0x49010 +#define _PIPE_A_CSC_COEFF_BY 0x49014 +#define _PIPE_A_CSC_COEFF_RU_GU 0x49018 +#define _PIPE_A_CSC_COEFF_BU 0x4901c +#define _PIPE_A_CSC_COEFF_RV_GV 0x49020 +#define _PIPE_A_CSC_COEFF_BV 0x49024 +#define _PIPE_A_CSC_MODE 0x49028 +#define _PIPE_A_CSC_PREOFF_HI 0x49030 +#define _PIPE_A_CSC_PREOFF_ME 0x49034 +#define _PIPE_A_CSC_PREOFF_LO 0x49038 +#define _PIPE_A_CSC_POSTOFF_HI 0x49040 +#define _PIPE_A_CSC_POSTOFF_ME 0x49044 +#define _PIPE_A_CSC_POSTOFF_LO 0x49048 + +#define _PIPE_B_CSC_COEFF_RY_GY 0x49110 +#define _PIPE_B_CSC_COEFF_BY 0x49114 +#define _PIPE_B_CSC_COEFF_RU_GU 0x49118 +#define _PIPE_B_CSC_COEFF_BU 0x4911c +#define _PIPE_B_CSC_COEFF_RV_GV 0x49120 +#define _PIPE_B_CSC_COEFF_BV 0x49124 +#define _PIPE_B_CSC_MODE 0x49128 +#define _PIPE_B_CSC_PREOFF_HI 0x49130 +#define _PIPE_B_CSC_PREOFF_ME 0x49134 +#define _PIPE_B_CSC_PREOFF_LO 0x49138 +#define _PIPE_B_CSC_POSTOFF_HI 0x49140 +#define _PIPE_B_CSC_POSTOFF_ME 0x49144 +#define _PIPE_B_CSC_POSTOFF_LO 0x49148 + +#define CSC_BLACK_SCREEN_OFFSET (1 << 2) +#define CSC_POSITION_BEFORE_GAMMA (1 << 1) +#define CSC_MODE_YUV_TO_RGB (1 << 0) + +#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) + #endif /* _I915_REG_H_ */ diff --git a/sys/dev/drm/i915/i915_suspend.c b/sys/dev/drm/i915/i915_suspend.c index a4e1b94245..2135f21ea4 100644 --- a/sys/dev/drm/i915/i915_suspend.c +++ b/sys/dev/drm/i915/i915_suspend.c @@ -29,67 +29,6 @@ #include "intel_drv.h" #include "i915_reg.h" -static bool i915_pipe_enabled(struct drm_device *dev, enum i915_pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpll_reg; - - /* On IVB, 3rd pipe shares PLL with another one */ - if (pipe > 1) - return false; - - if (HAS_PCH_SPLIT(dev)) - dpll_reg = _PCH_DPLL(pipe); - else - dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B; - - return (I915_READ(dpll_reg) & DPLL_VCO_ENABLE); -} - -static void i915_save_palette(struct drm_device *dev, enum i915_pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); - u32 *array; - int i; - - if (!i915_pipe_enabled(dev, pipe)) - return; - - if (HAS_PCH_SPLIT(dev)) - reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; - - if (pipe == PIPE_A) - array = dev_priv->regfile.save_palette_a; - else - array = dev_priv->regfile.save_palette_b; - - for (i = 0; i < 256; i++) - array[i] = I915_READ(reg + (i << 2)); -} - -static void i915_restore_palette(struct drm_device *dev, enum i915_pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long reg = (pipe == PIPE_A ? _PALETTE_A : _PALETTE_B); - u32 *array; - int i; - - if (!i915_pipe_enabled(dev, pipe)) - return; - - if (HAS_PCH_SPLIT(dev)) - reg = (pipe == PIPE_A) ? _LGC_PALETTE_A : _LGC_PALETTE_B; - - if (pipe == PIPE_A) - array = dev_priv->regfile.save_palette_a; - else - array = dev_priv->regfile.save_palette_b; - - for (i = 0; i < 256; i++) - I915_WRITE(reg + (i << 2), array[i]); -} - static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -130,6 +69,12 @@ static void i915_save_vga(struct drm_device *dev) int i; u16 cr_index, cr_data, st01; + /* VGA state */ + dev_priv->regfile.saveVGA0 = I915_READ(VGA0); + dev_priv->regfile.saveVGA1 = I915_READ(VGA1); + dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); + dev_priv->regfile.saveVGACNTRL = I915_READ(i915_vgacntrl_reg(dev)); + /* VGA color palette registers */ dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK); @@ -188,6 +133,15 @@ static void i915_restore_vga(struct drm_device *dev) int i; u16 cr_index, cr_data, st01; + /* VGA state */ + I915_WRITE(i915_vgacntrl_reg(dev), dev_priv->regfile.saveVGACNTRL); + + I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); + I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); + I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); + POSTING_READ(VGA_PD); + udelay(150); + /* MSR bits */ I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR); if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { @@ -235,396 +189,18 @@ static void i915_restore_vga(struct drm_device *dev) I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK); } -static void i915_save_modeset_reg(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return; - - /* Cursor state */ - dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR); - dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS); - dev_priv->regfile.saveCURABASE = I915_READ(_CURABASE); - dev_priv->regfile.saveCURBCNTR = I915_READ(_CURBCNTR); - dev_priv->regfile.saveCURBPOS = I915_READ(_CURBPOS); - dev_priv->regfile.saveCURBBASE = I915_READ(_CURBBASE); - if (IS_GEN2(dev)) - dev_priv->regfile.saveCURSIZE = I915_READ(CURSIZE); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePCH_DREF_CONTROL = I915_READ(PCH_DREF_CONTROL); - dev_priv->regfile.saveDISP_ARB_CTL = I915_READ(DISP_ARB_CTL); - } - - /* Pipe & plane A info */ - dev_priv->regfile.savePIPEACONF = I915_READ(_PIPEACONF); - dev_priv->regfile.savePIPEASRC = I915_READ(_PIPEASRC); - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveFPA0 = I915_READ(_PCH_FPA0); - dev_priv->regfile.saveFPA1 = I915_READ(_PCH_FPA1); - dev_priv->regfile.saveDPLL_A = I915_READ(_PCH_DPLL_A); - } else { - dev_priv->regfile.saveFPA0 = I915_READ(_FPA0); - dev_priv->regfile.saveFPA1 = I915_READ(_FPA1); - dev_priv->regfile.saveDPLL_A = I915_READ(_DPLL_A); - } - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveDPLL_A_MD = I915_READ(_DPLL_A_MD); - dev_priv->regfile.saveHTOTAL_A = I915_READ(_HTOTAL_A); - dev_priv->regfile.saveHBLANK_A = I915_READ(_HBLANK_A); - dev_priv->regfile.saveHSYNC_A = I915_READ(_HSYNC_A); - dev_priv->regfile.saveVTOTAL_A = I915_READ(_VTOTAL_A); - dev_priv->regfile.saveVBLANK_A = I915_READ(_VBLANK_A); - dev_priv->regfile.saveVSYNC_A = I915_READ(_VSYNC_A); - if (!HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveBCLRPAT_A = I915_READ(_BCLRPAT_A); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePIPEA_DATA_M1 = I915_READ(_PIPEA_DATA_M1); - dev_priv->regfile.savePIPEA_DATA_N1 = I915_READ(_PIPEA_DATA_N1); - dev_priv->regfile.savePIPEA_LINK_M1 = I915_READ(_PIPEA_LINK_M1); - dev_priv->regfile.savePIPEA_LINK_N1 = I915_READ(_PIPEA_LINK_N1); - - dev_priv->regfile.saveFDI_TXA_CTL = I915_READ(_FDI_TXA_CTL); - dev_priv->regfile.saveFDI_RXA_CTL = I915_READ(_FDI_RXA_CTL); - - dev_priv->regfile.savePFA_CTL_1 = I915_READ(_PFA_CTL_1); - dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ); - dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS); - - dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF); - dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A); - dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A); - dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A); - dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A); - dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A); - dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A); - } - - dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR); - dev_priv->regfile.saveDSPASTRIDE = I915_READ(_DSPASTRIDE); - dev_priv->regfile.saveDSPASIZE = I915_READ(_DSPASIZE); - dev_priv->regfile.saveDSPAPOS = I915_READ(_DSPAPOS); - dev_priv->regfile.saveDSPAADDR = I915_READ(_DSPAADDR); - if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->regfile.saveDSPASURF = I915_READ(_DSPASURF); - dev_priv->regfile.saveDSPATILEOFF = I915_READ(_DSPATILEOFF); - } - i915_save_palette(dev, PIPE_A); - dev_priv->regfile.savePIPEASTAT = I915_READ(_PIPEASTAT); - - /* Pipe & plane B info */ - dev_priv->regfile.savePIPEBCONF = I915_READ(_PIPEBCONF); - dev_priv->regfile.savePIPEBSRC = I915_READ(_PIPEBSRC); - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveFPB0 = I915_READ(_PCH_FPB0); - dev_priv->regfile.saveFPB1 = I915_READ(_PCH_FPB1); - dev_priv->regfile.saveDPLL_B = I915_READ(_PCH_DPLL_B); - } else { - dev_priv->regfile.saveFPB0 = I915_READ(_FPB0); - dev_priv->regfile.saveFPB1 = I915_READ(_FPB1); - dev_priv->regfile.saveDPLL_B = I915_READ(_DPLL_B); - } - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveDPLL_B_MD = I915_READ(_DPLL_B_MD); - dev_priv->regfile.saveHTOTAL_B = I915_READ(_HTOTAL_B); - dev_priv->regfile.saveHBLANK_B = I915_READ(_HBLANK_B); - dev_priv->regfile.saveHSYNC_B = I915_READ(_HSYNC_B); - dev_priv->regfile.saveVTOTAL_B = I915_READ(_VTOTAL_B); - dev_priv->regfile.saveVBLANK_B = I915_READ(_VBLANK_B); - dev_priv->regfile.saveVSYNC_B = I915_READ(_VSYNC_B); - if (!HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveBCLRPAT_B = I915_READ(_BCLRPAT_B); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePIPEB_DATA_M1 = I915_READ(_PIPEB_DATA_M1); - dev_priv->regfile.savePIPEB_DATA_N1 = I915_READ(_PIPEB_DATA_N1); - dev_priv->regfile.savePIPEB_LINK_M1 = I915_READ(_PIPEB_LINK_M1); - dev_priv->regfile.savePIPEB_LINK_N1 = I915_READ(_PIPEB_LINK_N1); - - dev_priv->regfile.saveFDI_TXB_CTL = I915_READ(_FDI_TXB_CTL); - dev_priv->regfile.saveFDI_RXB_CTL = I915_READ(_FDI_RXB_CTL); - - dev_priv->regfile.savePFB_CTL_1 = I915_READ(_PFB_CTL_1); - dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ); - dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS); - - dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF); - dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B); - dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B); - dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B); - dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B); - dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B); - dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B); - } - - dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR); - dev_priv->regfile.saveDSPBSTRIDE = I915_READ(_DSPBSTRIDE); - dev_priv->regfile.saveDSPBSIZE = I915_READ(_DSPBSIZE); - dev_priv->regfile.saveDSPBPOS = I915_READ(_DSPBPOS); - dev_priv->regfile.saveDSPBADDR = I915_READ(_DSPBADDR); - if (INTEL_INFO(dev)->gen >= 4) { - dev_priv->regfile.saveDSPBSURF = I915_READ(_DSPBSURF); - dev_priv->regfile.saveDSPBTILEOFF = I915_READ(_DSPBTILEOFF); - } - i915_save_palette(dev, PIPE_B); - dev_priv->regfile.savePIPEBSTAT = I915_READ(_PIPEBSTAT); - - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - for (i = 0; i < 16; i++) - dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - dev_priv->regfile.saveFENCE[i] = I915_READ64(FENCE_REG_965_0 + (i * 8)); - break; - case 3: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - dev_priv->regfile.saveFENCE[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4)); - case 2: - for (i = 0; i < 8; i++) - dev_priv->regfile.saveFENCE[i] = I915_READ(FENCE_REG_830_0 + (i * 4)); - break; - } - - /* CRT state */ - if (HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveADPA = I915_READ(PCH_ADPA); - else - dev_priv->regfile.saveADPA = I915_READ(ADPA); - - return; -} - -static void i915_restore_modeset_reg(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int dpll_a_reg, fpa0_reg, fpa1_reg; - int dpll_b_reg, fpb0_reg, fpb1_reg; - int i; - - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return; - - /* Fences */ - switch (INTEL_INFO(dev)->gen) { - case 7: - case 6: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); - break; - case 5: - case 4: - for (i = 0; i < 16; i++) - I915_WRITE64(FENCE_REG_965_0 + (i * 8), dev_priv->regfile.saveFENCE[i]); - break; - case 3: - case 2: - if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->regfile.saveFENCE[i+8]); - for (i = 0; i < 8; i++) - I915_WRITE(FENCE_REG_830_0 + (i * 4), dev_priv->regfile.saveFENCE[i]); - break; - } - - - if (HAS_PCH_SPLIT(dev)) { - dpll_a_reg = _PCH_DPLL_A; - dpll_b_reg = _PCH_DPLL_B; - fpa0_reg = _PCH_FPA0; - fpb0_reg = _PCH_FPB0; - fpa1_reg = _PCH_FPA1; - fpb1_reg = _PCH_FPB1; - } else { - dpll_a_reg = _DPLL_A; - dpll_b_reg = _DPLL_B; - fpa0_reg = _FPA0; - fpb0_reg = _FPB0; - fpa1_reg = _FPA1; - fpb1_reg = _FPB1; - } - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_DREF_CONTROL, dev_priv->regfile.savePCH_DREF_CONTROL); - I915_WRITE(DISP_ARB_CTL, dev_priv->regfile.saveDISP_ARB_CTL); - } - - /* Pipe & plane A info */ - /* Prime the clock */ - if (dev_priv->regfile.saveDPLL_A & DPLL_VCO_ENABLE) { - I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A & - ~DPLL_VCO_ENABLE); - POSTING_READ(dpll_a_reg); - udelay(150); - } - I915_WRITE(fpa0_reg, dev_priv->regfile.saveFPA0); - I915_WRITE(fpa1_reg, dev_priv->regfile.saveFPA1); - /* Actually enable it */ - I915_WRITE(dpll_a_reg, dev_priv->regfile.saveDPLL_A); - POSTING_READ(dpll_a_reg); - udelay(150); - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(_DPLL_A_MD, dev_priv->regfile.saveDPLL_A_MD); - POSTING_READ(_DPLL_A_MD); - } - udelay(150); - - /* Restore mode */ - I915_WRITE(_HTOTAL_A, dev_priv->regfile.saveHTOTAL_A); - I915_WRITE(_HBLANK_A, dev_priv->regfile.saveHBLANK_A); - I915_WRITE(_HSYNC_A, dev_priv->regfile.saveHSYNC_A); - I915_WRITE(_VTOTAL_A, dev_priv->regfile.saveVTOTAL_A); - I915_WRITE(_VBLANK_A, dev_priv->regfile.saveVBLANK_A); - I915_WRITE(_VSYNC_A, dev_priv->regfile.saveVSYNC_A); - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(_BCLRPAT_A, dev_priv->regfile.saveBCLRPAT_A); - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(_PIPEA_DATA_M1, dev_priv->regfile.savePIPEA_DATA_M1); - I915_WRITE(_PIPEA_DATA_N1, dev_priv->regfile.savePIPEA_DATA_N1); - I915_WRITE(_PIPEA_LINK_M1, dev_priv->regfile.savePIPEA_LINK_M1); - I915_WRITE(_PIPEA_LINK_N1, dev_priv->regfile.savePIPEA_LINK_N1); - - I915_WRITE(_FDI_RXA_CTL, dev_priv->regfile.saveFDI_RXA_CTL); - I915_WRITE(_FDI_TXA_CTL, dev_priv->regfile.saveFDI_TXA_CTL); - - I915_WRITE(_PFA_CTL_1, dev_priv->regfile.savePFA_CTL_1); - I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ); - I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS); - - I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF); - I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A); - I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A); - I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A); - I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A); - I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A); - I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A); - } - - /* Restore plane info */ - I915_WRITE(_DSPASIZE, dev_priv->regfile.saveDSPASIZE); - I915_WRITE(_DSPAPOS, dev_priv->regfile.saveDSPAPOS); - I915_WRITE(_PIPEASRC, dev_priv->regfile.savePIPEASRC); - I915_WRITE(_DSPAADDR, dev_priv->regfile.saveDSPAADDR); - I915_WRITE(_DSPASTRIDE, dev_priv->regfile.saveDSPASTRIDE); - if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(_DSPASURF, dev_priv->regfile.saveDSPASURF); - I915_WRITE(_DSPATILEOFF, dev_priv->regfile.saveDSPATILEOFF); - } - - I915_WRITE(_PIPEACONF, dev_priv->regfile.savePIPEACONF); - - i915_restore_palette(dev, PIPE_A); - /* Enable the plane */ - I915_WRITE(_DSPACNTR, dev_priv->regfile.saveDSPACNTR); - I915_WRITE(_DSPAADDR, I915_READ(_DSPAADDR)); - - /* Pipe & plane B info */ - if (dev_priv->regfile.saveDPLL_B & DPLL_VCO_ENABLE) { - I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B & - ~DPLL_VCO_ENABLE); - POSTING_READ(dpll_b_reg); - udelay(150); - } - I915_WRITE(fpb0_reg, dev_priv->regfile.saveFPB0); - I915_WRITE(fpb1_reg, dev_priv->regfile.saveFPB1); - /* Actually enable it */ - I915_WRITE(dpll_b_reg, dev_priv->regfile.saveDPLL_B); - POSTING_READ(dpll_b_reg); - udelay(150); - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) { - I915_WRITE(_DPLL_B_MD, dev_priv->regfile.saveDPLL_B_MD); - POSTING_READ(_DPLL_B_MD); - } - udelay(150); - - /* Restore mode */ - I915_WRITE(_HTOTAL_B, dev_priv->regfile.saveHTOTAL_B); - I915_WRITE(_HBLANK_B, dev_priv->regfile.saveHBLANK_B); - I915_WRITE(_HSYNC_B, dev_priv->regfile.saveHSYNC_B); - I915_WRITE(_VTOTAL_B, dev_priv->regfile.saveVTOTAL_B); - I915_WRITE(_VBLANK_B, dev_priv->regfile.saveVBLANK_B); - I915_WRITE(_VSYNC_B, dev_priv->regfile.saveVSYNC_B); - if (!HAS_PCH_SPLIT(dev)) - I915_WRITE(_BCLRPAT_B, dev_priv->regfile.saveBCLRPAT_B); - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(_PIPEB_DATA_M1, dev_priv->regfile.savePIPEB_DATA_M1); - I915_WRITE(_PIPEB_DATA_N1, dev_priv->regfile.savePIPEB_DATA_N1); - I915_WRITE(_PIPEB_LINK_M1, dev_priv->regfile.savePIPEB_LINK_M1); - I915_WRITE(_PIPEB_LINK_N1, dev_priv->regfile.savePIPEB_LINK_N1); - - I915_WRITE(_FDI_RXB_CTL, dev_priv->regfile.saveFDI_RXB_CTL); - I915_WRITE(_FDI_TXB_CTL, dev_priv->regfile.saveFDI_TXB_CTL); - - I915_WRITE(_PFB_CTL_1, dev_priv->regfile.savePFB_CTL_1); - I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ); - I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS); - - I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF); - I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B); - I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B); - I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B); - I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B); - I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B); - I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B); - } - - /* Restore plane info */ - I915_WRITE(_DSPBSIZE, dev_priv->regfile.saveDSPBSIZE); - I915_WRITE(_DSPBPOS, dev_priv->regfile.saveDSPBPOS); - I915_WRITE(_PIPEBSRC, dev_priv->regfile.savePIPEBSRC); - I915_WRITE(_DSPBADDR, dev_priv->regfile.saveDSPBADDR); - I915_WRITE(_DSPBSTRIDE, dev_priv->regfile.saveDSPBSTRIDE); - if (INTEL_INFO(dev)->gen >= 4) { - I915_WRITE(_DSPBSURF, dev_priv->regfile.saveDSPBSURF); - I915_WRITE(_DSPBTILEOFF, dev_priv->regfile.saveDSPBTILEOFF); - } - - I915_WRITE(_PIPEBCONF, dev_priv->regfile.savePIPEBCONF); - - i915_restore_palette(dev, PIPE_B); - /* Enable the plane */ - I915_WRITE(_DSPBCNTR, dev_priv->regfile.saveDSPBCNTR); - I915_WRITE(_DSPBADDR, I915_READ(_DSPBADDR)); - - /* Cursor state */ - I915_WRITE(_CURAPOS, dev_priv->regfile.saveCURAPOS); - I915_WRITE(_CURACNTR, dev_priv->regfile.saveCURACNTR); - I915_WRITE(_CURABASE, dev_priv->regfile.saveCURABASE); - I915_WRITE(_CURBPOS, dev_priv->regfile.saveCURBPOS); - I915_WRITE(_CURBCNTR, dev_priv->regfile.saveCURBCNTR); - I915_WRITE(_CURBBASE, dev_priv->regfile.saveCURBBASE); - if (IS_GEN2(dev)) - I915_WRITE(CURSIZE, dev_priv->regfile.saveCURSIZE); - - /* CRT state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(PCH_ADPA, dev_priv->regfile.saveADPA); - else - I915_WRITE(ADPA, dev_priv->regfile.saveADPA); - - return; -} - static void i915_save_display(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; /* Display arbitration control */ - dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); + if (INTEL_INFO(dev)->gen <= 4) + dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); /* This is only meaningful in non-KMS mode */ /* Don't regfile.save them in KMS mode */ - i915_save_modeset_reg(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_save_display_reg(dev); /* LVDS state */ if (HAS_PCH_SPLIT(dev)) { @@ -658,24 +234,6 @@ static void i915_save_display(struct drm_device *dev) dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR); } - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - dev_priv->regfile.saveDP_B = I915_READ(DP_B); - dev_priv->regfile.saveDP_C = I915_READ(DP_C); - dev_priv->regfile.saveDP_D = I915_READ(DP_D); - dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); - dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); - dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); - dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); - dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); - dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); - dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); - dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); - } - /* FIXME: regfile.save TV & SDVO state */ - } - /* Only regfile.save FBC state on the platform that supports FBC */ if (I915_HAS_FBC(dev)) { if (HAS_PCH_SPLIT(dev)) { @@ -690,16 +248,8 @@ static void i915_save_display(struct drm_device *dev) } } - /* VGA state */ - dev_priv->regfile.saveVGA0 = I915_READ(VGA0); - dev_priv->regfile.saveVGA1 = I915_READ(VGA1); - dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); - if (HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL); - else - dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL); - - i915_save_vga(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_save_vga(dev); } static void i915_restore_display(struct drm_device *dev) @@ -707,25 +257,11 @@ static void i915_restore_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* Display arbitration */ - I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); + if (INTEL_INFO(dev)->gen <= 4) + I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display port ratios (must be done before clock is set) */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); - I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); - I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); - I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); - I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); - I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); - I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); - I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); - } - } - - /* This is only meaningful in non-KMS mode */ - /* Don't restore them in KMS mode */ - i915_restore_modeset_reg(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_restore_display_reg(dev); /* LVDS state */ if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) @@ -763,16 +299,6 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); } - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(DP_B, dev_priv->regfile.saveDP_B); - I915_WRITE(DP_C, dev_priv->regfile.saveDP_C); - I915_WRITE(DP_D, dev_priv->regfile.saveDP_D); - } - /* FIXME: restore TV & SDVO state */ - } - /* only restore FBC info on the platform that supports FBC*/ intel_disable_fbc(dev); if (I915_HAS_FBC(dev)) { @@ -787,19 +313,11 @@ static void i915_restore_display(struct drm_device *dev) I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); } } - /* VGA state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL); - else - I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL); - I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); - I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); - I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); - POSTING_READ(VGA_PD); - udelay(150); - - i915_restore_vga(dev); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + i915_restore_vga(dev); + else + i915_redisable_vga(dev); } int i915_save_state(struct drm_device *dev) @@ -809,7 +327,7 @@ int i915_save_state(struct drm_device *dev) pci_read_config_byte(dev->pdev, LBB, &dev_priv->regfile.saveLBB); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); i915_save_display(dev); @@ -847,7 +365,7 @@ int i915_save_state(struct drm_device *dev) for (i = 0; i < 3; i++) dev_priv->regfile.saveSWF2[i] = I915_READ(SWF30 + (i << 2)); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -859,7 +377,7 @@ int i915_restore_state(struct drm_device *dev) pci_write_config_byte(dev->pdev, LBB, dev_priv->regfile.saveLBB); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); i915_restore_display(dev); @@ -892,7 +410,7 @@ int i915_restore_state(struct drm_device *dev) for (i = 0; i < 3; i++) I915_WRITE(SWF30 + (i << 2), dev_priv->regfile.saveSWF2[i]); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); intel_i2c_reset(dev); diff --git a/sys/dev/drm/i915/i915_trace.h b/sys/dev/drm/i915/i915_trace.h new file mode 100644 index 0000000000..1541324715 --- /dev/null +++ b/sys/dev/drm/i915/i915_trace.h @@ -0,0 +1,45 @@ +/* + * + * Copyright 1014 François Tigeot + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _I915_TRACE_H_ +#define _I915_TRACE_H_ + +#define trace_i915_gem_evict(a,b,c,d) +#define trace_i915_gem_evict_everything(a) + +#define trace_i915_gem_object_change_domain(a,b,c) + +#define trace_i915_ring_wait_begin(a) +#define trace_i915_ring_wait_end(a) +#define trace_i915_gem_ring_dispatch(a,b,c) +#define trace_i915_gem_ring_flush(a,b,c) + +#define trace_i915_reg_rw(a,b,c,d) + +#define trace_intel_gpu_freq_change(a) + +#endif /* _I915_TRACE_H_ */ diff --git a/sys/dev/drm/i915/i915_suspend.c b/sys/dev/drm/i915/i915_ums.c similarity index 52% copy from sys/dev/drm/i915/i915_suspend.c copy to sys/dev/drm/i915/i915_ums.c index a4e1b94245..6c4ccff9e5 100644 --- a/sys/dev/drm/i915/i915_suspend.c +++ b/sys/dev/drm/i915/i915_ums.c @@ -2,6 +2,8 @@ * * Copyright 2008 (c) Intel Corporation * Jesse Barnes + * Copyright 2013 (c) Intel Corporation + * Daniel Vetter * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -90,159 +92,11 @@ static void i915_restore_palette(struct drm_device *dev, enum i915_pipe pipe) I915_WRITE(reg + (i << 2), array[i]); } -static u8 i915_read_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE8(index_port, reg); - return I915_READ8(data_port); -} - -static u8 i915_read_ar(struct drm_device *dev, u16 st01, u8 reg, u16 palette_enable) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_READ8(st01); - I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); - return I915_READ8(VGA_AR_DATA_READ); -} - -static void i915_write_ar(struct drm_device *dev, u16 st01, u8 reg, u8 val, u16 palette_enable) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_READ8(st01); - I915_WRITE8(VGA_AR_INDEX, palette_enable | reg); - I915_WRITE8(VGA_AR_DATA_WRITE, val); -} - -static void i915_write_indexed(struct drm_device *dev, u16 index_port, u16 data_port, u8 reg, u8 val) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - I915_WRITE8(index_port, reg); - I915_WRITE8(data_port, val); -} - -static void i915_save_vga(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - u16 cr_index, cr_data, st01; - - /* VGA color palette registers */ - dev_priv->regfile.saveDACMASK = I915_READ8(VGA_DACMASK); - - /* MSR bits */ - dev_priv->regfile.saveMSR = I915_READ8(VGA_MSR_READ); - if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { - cr_index = VGA_CR_INDEX_CGA; - cr_data = VGA_CR_DATA_CGA; - st01 = VGA_ST01_CGA; - } else { - cr_index = VGA_CR_INDEX_MDA; - cr_data = VGA_CR_DATA_MDA; - st01 = VGA_ST01_MDA; - } - - /* CRT controller regs */ - i915_write_indexed(dev, cr_index, cr_data, 0x11, - i915_read_indexed(dev, cr_index, cr_data, 0x11) & - (~0x80)); - for (i = 0; i <= 0x24; i++) - dev_priv->regfile.saveCR[i] = - i915_read_indexed(dev, cr_index, cr_data, i); - /* Make sure we don't turn off CR group 0 writes */ - dev_priv->regfile.saveCR[0x11] &= ~0x80; - - /* Attribute controller registers */ - I915_READ8(st01); - dev_priv->regfile.saveAR_INDEX = I915_READ8(VGA_AR_INDEX); - for (i = 0; i <= 0x14; i++) - dev_priv->regfile.saveAR[i] = i915_read_ar(dev, st01, i, 0); - I915_READ8(st01); - I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX); - I915_READ8(st01); - - /* Graphics controller registers */ - for (i = 0; i < 9; i++) - dev_priv->regfile.saveGR[i] = - i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i); - - dev_priv->regfile.saveGR[0x10] = - i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10); - dev_priv->regfile.saveGR[0x11] = - i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11); - dev_priv->regfile.saveGR[0x18] = - i915_read_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18); - - /* Sequencer registers */ - for (i = 0; i < 8; i++) - dev_priv->regfile.saveSR[i] = - i915_read_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i); -} - -static void i915_restore_vga(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - u16 cr_index, cr_data, st01; - - /* MSR bits */ - I915_WRITE8(VGA_MSR_WRITE, dev_priv->regfile.saveMSR); - if (dev_priv->regfile.saveMSR & VGA_MSR_CGA_MODE) { - cr_index = VGA_CR_INDEX_CGA; - cr_data = VGA_CR_DATA_CGA; - st01 = VGA_ST01_CGA; - } else { - cr_index = VGA_CR_INDEX_MDA; - cr_data = VGA_CR_DATA_MDA; - st01 = VGA_ST01_MDA; - } - - /* Sequencer registers, don't write SR07 */ - for (i = 0; i < 7; i++) - i915_write_indexed(dev, VGA_SR_INDEX, VGA_SR_DATA, i, - dev_priv->regfile.saveSR[i]); - - /* CRT controller regs */ - /* Enable CR group 0 writes */ - i915_write_indexed(dev, cr_index, cr_data, 0x11, dev_priv->regfile.saveCR[0x11]); - for (i = 0; i <= 0x24; i++) - i915_write_indexed(dev, cr_index, cr_data, i, dev_priv->regfile.saveCR[i]); - - /* Graphics controller regs */ - for (i = 0; i < 9; i++) - i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, i, - dev_priv->regfile.saveGR[i]); - - i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x10, - dev_priv->regfile.saveGR[0x10]); - i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x11, - dev_priv->regfile.saveGR[0x11]); - i915_write_indexed(dev, VGA_GR_INDEX, VGA_GR_DATA, 0x18, - dev_priv->regfile.saveGR[0x18]); - - /* Attribute controller registers */ - I915_READ8(st01); /* switch back to index mode */ - for (i = 0; i <= 0x14; i++) - i915_write_ar(dev, st01, i, dev_priv->regfile.saveAR[i], 0); - I915_READ8(st01); /* switch back to index mode */ - I915_WRITE8(VGA_AR_INDEX, dev_priv->regfile.saveAR_INDEX | 0x20); - I915_READ8(st01); - - /* VGA color palette registers */ - I915_WRITE8(VGA_DACMASK, dev_priv->regfile.saveDACMASK); -} - -static void i915_save_modeset_reg(struct drm_device *dev) +void i915_save_display_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int i; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return; - /* Cursor state */ dev_priv->regfile.saveCURACNTR = I915_READ(_CURACNTR); dev_priv->regfile.saveCURAPOS = I915_READ(_CURAPOS); @@ -400,18 +254,43 @@ static void i915_save_modeset_reg(struct drm_device *dev) else dev_priv->regfile.saveADPA = I915_READ(ADPA); + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + dev_priv->regfile.saveDP_B = I915_READ(DP_B); + dev_priv->regfile.saveDP_C = I915_READ(DP_C); + dev_priv->regfile.saveDP_D = I915_READ(DP_D); + dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); + dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); + dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); + dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); + dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); + dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); + dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); + dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); + } + /* FIXME: regfile.save TV & SDVO state */ + return; } -static void i915_restore_modeset_reg(struct drm_device *dev) +void i915_restore_display_reg(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; int dpll_a_reg, fpa0_reg, fpa1_reg; int dpll_b_reg, fpb0_reg, fpb1_reg; int i; - if (drm_core_check_feature(dev, DRIVER_MODESET)) - return; + /* Display port ratios (must be done before clock is set) */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); + I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); + I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); + I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); + I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); + I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); + I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); + I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); + } /* Fences */ switch (INTEL_INFO(dev)->gen) { @@ -612,289 +491,13 @@ static void i915_restore_modeset_reg(struct drm_device *dev) else I915_WRITE(ADPA, dev_priv->regfile.saveADPA); - return; -} - -static void i915_save_display(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* Display arbitration control */ - dev_priv->regfile.saveDSPARB = I915_READ(DSPARB); - - /* This is only meaningful in non-KMS mode */ - /* Don't regfile.save them in KMS mode */ - i915_save_modeset_reg(dev); - - /* LVDS state */ - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL); - dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1); - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2); - dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL); - dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2); - dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS); - } else { - dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL); - dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS); - dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL); - dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL); - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2); - if (IS_MOBILE(dev) && !IS_I830(dev)) - dev_priv->regfile.saveLVDS = I915_READ(LVDS); - } - - if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) - dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL); - - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PCH_PP_ON_DELAYS); - dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PCH_PP_OFF_DELAYS); - dev_priv->regfile.savePP_DIVISOR = I915_READ(PCH_PP_DIVISOR); - } else { - dev_priv->regfile.savePP_ON_DELAYS = I915_READ(PP_ON_DELAYS); - dev_priv->regfile.savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS); - dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR); - } - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - dev_priv->regfile.saveDP_B = I915_READ(DP_B); - dev_priv->regfile.saveDP_C = I915_READ(DP_C); - dev_priv->regfile.saveDP_D = I915_READ(DP_D); - dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M); - dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M); - dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N); - dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N); - dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M); - dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M); - dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N); - dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N); - } - /* FIXME: regfile.save TV & SDVO state */ + /* Display Port state */ + if (SUPPORTS_INTEGRATED_DP(dev)) { + I915_WRITE(DP_B, dev_priv->regfile.saveDP_B); + I915_WRITE(DP_C, dev_priv->regfile.saveDP_C); + I915_WRITE(DP_D, dev_priv->regfile.saveDP_D); } + /* FIXME: restore TV & SDVO state */ - /* Only regfile.save FBC state on the platform that supports FBC */ - if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); - } else if (IS_GM45(dev)) { - dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); - } else { - dev_priv->regfile.saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); - dev_priv->regfile.saveFBC_LL_BASE = I915_READ(FBC_LL_BASE); - dev_priv->regfile.saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2); - dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL); - } - } - - /* VGA state */ - dev_priv->regfile.saveVGA0 = I915_READ(VGA0); - dev_priv->regfile.saveVGA1 = I915_READ(VGA1); - dev_priv->regfile.saveVGA_PD = I915_READ(VGA_PD); - if (HAS_PCH_SPLIT(dev)) - dev_priv->regfile.saveVGACNTRL = I915_READ(CPU_VGACNTRL); - else - dev_priv->regfile.saveVGACNTRL = I915_READ(VGACNTRL); - - i915_save_vga(dev); -} - -static void i915_restore_display(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* Display arbitration */ - I915_WRITE(DSPARB, dev_priv->regfile.saveDSPARB); - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display port ratios (must be done before clock is set) */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M); - I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M); - I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N); - I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N); - I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M); - I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M); - I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N); - I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N); - } - } - - /* This is only meaningful in non-KMS mode */ - /* Don't restore them in KMS mode */ - i915_restore_modeset_reg(dev); - - /* LVDS state */ - if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) - I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(PCH_LVDS, dev_priv->regfile.saveLVDS); - } else if (IS_MOBILE(dev) && !IS_I830(dev)) - I915_WRITE(LVDS, dev_priv->regfile.saveLVDS); - - if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev)) - I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL); - - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL); - I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2); - /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2; - * otherwise we get blank eDP screen after S3 on some machines - */ - I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2); - I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL); - I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); - I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); - I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); - I915_WRITE(PCH_PP_CONTROL, dev_priv->regfile.savePP_CONTROL); - I915_WRITE(RSTDBYCTL, - dev_priv->regfile.saveMCHBAR_RENDER_STANDBY); - } else { - I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS); - I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL); - I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL); - I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS); - I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS); - I915_WRITE(PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR); - I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL); - } - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Display Port state */ - if (SUPPORTS_INTEGRATED_DP(dev)) { - I915_WRITE(DP_B, dev_priv->regfile.saveDP_B); - I915_WRITE(DP_C, dev_priv->regfile.saveDP_C); - I915_WRITE(DP_D, dev_priv->regfile.saveDP_D); - } - /* FIXME: restore TV & SDVO state */ - } - - /* only restore FBC info on the platform that supports FBC*/ - intel_disable_fbc(dev); - if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); - } else if (IS_GM45(dev)) { - I915_WRITE(DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE); - } else { - I915_WRITE(FBC_CFB_BASE, dev_priv->regfile.saveFBC_CFB_BASE); - I915_WRITE(FBC_LL_BASE, dev_priv->regfile.saveFBC_LL_BASE); - I915_WRITE(FBC_CONTROL2, dev_priv->regfile.saveFBC_CONTROL2); - I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL); - } - } - /* VGA state */ - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(CPU_VGACNTRL, dev_priv->regfile.saveVGACNTRL); - else - I915_WRITE(VGACNTRL, dev_priv->regfile.saveVGACNTRL); - - I915_WRITE(VGA0, dev_priv->regfile.saveVGA0); - I915_WRITE(VGA1, dev_priv->regfile.saveVGA1); - I915_WRITE(VGA_PD, dev_priv->regfile.saveVGA_PD); - POSTING_READ(VGA_PD); - udelay(150); - - i915_restore_vga(dev); -} - -int i915_save_state(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - pci_read_config_byte(dev->pdev, LBB, &dev_priv->regfile.saveLBB); - - DRM_LOCK(dev); - - i915_save_display(dev); - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Interrupt state */ - if (HAS_PCH_SPLIT(dev)) { - dev_priv->regfile.saveDEIER = I915_READ(DEIER); - dev_priv->regfile.saveDEIMR = I915_READ(DEIMR); - dev_priv->regfile.saveGTIER = I915_READ(GTIER); - dev_priv->regfile.saveGTIMR = I915_READ(GTIMR); - dev_priv->regfile.saveFDI_RXA_IMR = I915_READ(_FDI_RXA_IMR); - dev_priv->regfile.saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); - dev_priv->regfile.saveMCHBAR_RENDER_STANDBY = - I915_READ(RSTDBYCTL); - dev_priv->regfile.savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); - } else { - dev_priv->regfile.saveIER = I915_READ(IER); - dev_priv->regfile.saveIMR = I915_READ(IMR); - } - } - - intel_disable_gt_powersave(dev); - - /* Cache mode state */ - dev_priv->regfile.saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0); - - /* Memory Arbitration state */ - dev_priv->regfile.saveMI_ARB_STATE = I915_READ(MI_ARB_STATE); - - /* Scratch space */ - for (i = 0; i < 16; i++) { - dev_priv->regfile.saveSWF0[i] = I915_READ(SWF00 + (i << 2)); - dev_priv->regfile.saveSWF1[i] = I915_READ(SWF10 + (i << 2)); - } - for (i = 0; i < 3; i++) - dev_priv->regfile.saveSWF2[i] = I915_READ(SWF30 + (i << 2)); - - DRM_UNLOCK(dev); - - return 0; -} - -int i915_restore_state(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - pci_write_config_byte(dev->pdev, LBB, dev_priv->regfile.saveLBB); - - DRM_LOCK(dev); - - i915_restore_display(dev); - - if (!drm_core_check_feature(dev, DRIVER_MODESET)) { - /* Interrupt state */ - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(DEIER, dev_priv->regfile.saveDEIER); - I915_WRITE(DEIMR, dev_priv->regfile.saveDEIMR); - I915_WRITE(GTIER, dev_priv->regfile.saveGTIER); - I915_WRITE(GTIMR, dev_priv->regfile.saveGTIMR); - I915_WRITE(_FDI_RXA_IMR, dev_priv->regfile.saveFDI_RXA_IMR); - I915_WRITE(_FDI_RXB_IMR, dev_priv->regfile.saveFDI_RXB_IMR); - I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->regfile.savePCH_PORT_HOTPLUG); - } else { - I915_WRITE(IER, dev_priv->regfile.saveIER); - I915_WRITE(IMR, dev_priv->regfile.saveIMR); - } - } - - /* Cache mode state */ - I915_WRITE(CACHE_MODE_0, dev_priv->regfile.saveCACHE_MODE_0 | 0xffff0000); - - /* Memory arbitration state */ - I915_WRITE(MI_ARB_STATE, dev_priv->regfile.saveMI_ARB_STATE | 0xffff0000); - - for (i = 0; i < 16; i++) { - I915_WRITE(SWF00 + (i << 2), dev_priv->regfile.saveSWF0[i]); - I915_WRITE(SWF10 + (i << 2), dev_priv->regfile.saveSWF1[i]); - } - for (i = 0; i < 3; i++) - I915_WRITE(SWF30 + (i << 2), dev_priv->regfile.saveSWF2[i]); - - DRM_UNLOCK(dev); - - intel_i2c_reset(dev); - - return 0; + return; } diff --git a/sys/dev/drm/i915/intel_crt.c b/sys/dev/drm/i915/intel_crt.c index 756127d3e2..8886d4da29 100644 --- a/sys/dev/drm/i915/intel_crt.c +++ b/sys/dev/drm/i915/intel_crt.c @@ -257,27 +257,27 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) crt->force_hotplug_required = 0; - save_adpa = adpa = I915_READ(PCH_ADPA); + save_adpa = adpa = I915_READ(crt->adpa_reg); DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; if (turn_off_dac) adpa &= ~ADPA_DAC_ENABLE; - I915_WRITE(PCH_ADPA, adpa); + I915_WRITE(crt->adpa_reg, adpa); - if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000)) DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); if (turn_off_dac) { - I915_WRITE(PCH_ADPA, save_adpa); - POSTING_READ(PCH_ADPA); + I915_WRITE(crt->adpa_reg, save_adpa); + POSTING_READ(crt->adpa_reg); } } /* Check the status to see if both blue and green are on now */ - adpa = I915_READ(PCH_ADPA); + adpa = I915_READ(crt->adpa_reg); if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else @@ -290,26 +290,27 @@ static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) static bool valleyview_crt_detect_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct intel_crt *crt = intel_attached_crt(connector); struct drm_i915_private *dev_priv = dev->dev_private; u32 adpa; bool ret; u32 save_adpa; - save_adpa = adpa = I915_READ(ADPA); + save_adpa = adpa = I915_READ(crt->adpa_reg); DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa); adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER; - I915_WRITE(ADPA, adpa); + I915_WRITE(crt->adpa_reg, adpa); - if (wait_for((I915_READ(ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, + if (wait_for((I915_READ(crt->adpa_reg) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0, 1000)) { DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER"); - I915_WRITE(ADPA, save_adpa); + I915_WRITE(crt->adpa_reg, save_adpa); } /* Check the status to see if both blue and green are on now */ - adpa = I915_READ(ADPA); + adpa = I915_READ(crt->adpa_reg); if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0) ret = true; else @@ -657,11 +658,11 @@ static void intel_crt_reset(struct drm_connector *connector) if (HAS_PCH_SPLIT(dev)) { u32 adpa; - adpa = I915_READ(PCH_ADPA); + adpa = I915_READ(crt->adpa_reg); adpa &= ~ADPA_CRT_HOTPLUG_MASK; adpa |= ADPA_HOTPLUG_BITS; - I915_WRITE(PCH_ADPA, adpa); - POSTING_READ(PCH_ADPA); + I915_WRITE(crt->adpa_reg, adpa); + POSTING_READ(crt->adpa_reg); DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa); crt->force_hotplug_required = 1; @@ -770,7 +771,7 @@ void intel_crt_init(struct drm_device *dev) crt->base.disable = intel_disable_crt; crt->base.enable = intel_enable_crt; - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) crt->base.get_hw_state = intel_ddi_get_hw_state; else crt->base.get_hw_state = intel_crt_get_hw_state; diff --git a/sys/dev/drm/i915/intel_ddi.c b/sys/dev/drm/i915/intel_ddi.c index 2b68a58849..f3ea7a20c0 100644 --- a/sys/dev/drm/i915/intel_ddi.c +++ b/sys/dev/drm/i915/intel_ddi.c @@ -116,16 +116,17 @@ void intel_prepare_ddi(struct drm_device *dev) { int port; - if (IS_HASWELL(dev)) { - for (port = PORT_A; port < PORT_E; port++) - intel_prepare_ddi_buffers(dev, port, false); + if (!HAS_DDI(dev)) + return; - /* DDI E is the suggested one to work in FDI mode, so program is as such by - * default. It will have to be re-programmed in case a digital DP output - * will be detected on it - */ - intel_prepare_ddi_buffers(dev, PORT_E, true); - } + for (port = PORT_A; port < PORT_E; port++) + intel_prepare_ddi_buffers(dev, port, false); + + /* DDI E is the suggested one to work in FDI mode, so program is as such + * by default. It will have to be re-programmed in case a digital DP + * output will be detected on it + */ + intel_prepare_ddi_buffers(dev, PORT_E, true); } static const long hsw_ddi_buf_ctl_values[] = { @@ -678,6 +679,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder, DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); + intel_crtc->eld_vld = false; if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_digital_port *intel_dig_port = @@ -991,7 +993,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc *crtc) if (cpu_transcoder == TRANSCODER_EDP) { switch (pipe) { case PIPE_A: - temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + /* Can only use the always-on power well for eDP when + * not using the panel fitter, and when not using motion + * blur mitigation (which we don't support). */ + if (dev_priv->pch_pf_size) + temp |= TRANS_DDI_EDP_INPUT_A_ONOFF; + else + temp |= TRANS_DDI_EDP_INPUT_A_ON; break; case PIPE_B: temp |= TRANS_DDI_EDP_INPUT_B_ONOFF; @@ -1075,7 +1083,7 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) if (port == PORT_A) cpu_transcoder = TRANSCODER_EDP; else - cpu_transcoder = pipe; + cpu_transcoder = (enum transcoder) pipe; tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); @@ -1291,10 +1299,14 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) static void intel_enable_ddi(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_ddi_get_encoder_port(intel_encoder); int type = intel_encoder->type; + uint32_t tmp; if (type == INTEL_OUTPUT_HDMI) { struct intel_digital_port *intel_dig_port = @@ -1311,18 +1323,34 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder) ironlake_edp_backlight_on(intel_dp); } + + if (intel_crtc->eld_vld) { + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); + } } static void intel_disable_ddi(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; int type = intel_encoder->type; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ironlake_edp_backlight_off(intel_dp); } + + tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD); + tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4)); + I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp); } int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv) @@ -1364,8 +1392,8 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) struct intel_dp *intel_dp = &intel_dig_port->dp; struct drm_i915_private *dev_priv = encoder->dev->dev_private; enum port port = intel_dig_port->port; - bool wait = false; uint32_t val; + bool wait = false; if (I915_READ(DP_TP_CTL(port)) & DP_TP_CTL_ENABLE) { val = I915_READ(DDI_BUF_CTL(port)); diff --git a/sys/dev/drm/i915/intel_display.c b/sys/dev/drm/i915/intel_display.c index 79cf598da1..63a3be9a13 100644 --- a/sys/dev/drm/i915/intel_display.c +++ b/sys/dev/drm/i915/intel_display.c @@ -164,8 +164,8 @@ static const intel_limit_t intel_limits_i9xx_lvds = { .vco = { .min = 1400000, .max = 2800000 }, .n = { .min = 1, .max = 6 }, .m = { .min = 70, .max = 120 }, - .m1 = { .min = 10, .max = 22 }, - .m2 = { .min = 5, .max = 9 }, + .m1 = { .min = 8, .max = 18 }, + .m2 = { .min = 3, .max = 7 }, .p = { .min = 7, .max = 98 }, .p1 = { .min = 1, .max = 8 }, .p2 = { .dot_limit = 112000, @@ -412,12 +412,11 @@ static const intel_limit_t intel_limits_vlv_dp = { u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) { - u32 val = 0; + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); - spin_lock(&dev_priv->dpio_lock); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO idle wait timed out\n"); - goto out_unlock; + return 0; } I915_WRITE(DPIO_REG, reg); @@ -425,22 +424,20 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) DPIO_BYTE); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO read wait timed out\n"); - goto out_unlock; + return 0; } - val = I915_READ(DPIO_DATA); -out_unlock: - spin_unlock(&dev_priv->dpio_lock); - return val; + return I915_READ(DPIO_DATA); } static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val) { - spin_lock(&dev_priv->dpio_lock); + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { DRM_ERROR("DPIO idle wait timed out\n"); - goto out_unlock; + return; } I915_WRITE(DPIO_DATA, val); @@ -449,9 +446,6 @@ static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, DPIO_BYTE); if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) DRM_ERROR("DPIO write wait timed out\n"); - -out_unlock: - spin_unlock(&dev_priv->dpio_lock); } static void vlv_init_dpio(struct drm_device *dev) @@ -465,61 +459,14 @@ static void vlv_init_dpio(struct drm_device *dev) POSTING_READ(DPIO_CTL); } -static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) -{ - DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident); - return 1; -} - -static const struct dmi_system_id intel_dual_link_lvds[] = { - { - .callback = intel_dual_link_lvds_callback, - .ident = "Apple MacBook Pro (Core i5/i7 Series)", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), - }, - }, - { } /* terminating entry */ -}; - -static bool is_dual_link_lvds(struct drm_i915_private *dev_priv, - unsigned int reg) -{ - unsigned int val; - - /* use the module option value if specified */ - if (i915_lvds_channel_mode > 0) - return i915_lvds_channel_mode == 2; - - if (dmi_check_system(intel_dual_link_lvds)) - return true; - - if (dev_priv->lvds_val) - val = dev_priv->lvds_val; - else { - /* BIOS should set the proper LVDS register value at boot, but - * in reality, it doesn't set the value when the lid is closed; - * we need to check "the value to be set" in VBT when LVDS - * register is uninitialized. - */ - val = I915_READ(reg); - if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) - val = dev_priv->bios_lvds_val; - dev_priv->lvds_val = val; - } - return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; -} - static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, int refclk) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if (is_dual_link_lvds(dev_priv, PCH_LVDS)) { + if (intel_is_dual_link_lvds(dev)) { /* LVDS dual channel */ if (refclk == 100000) limit = &intel_limits_ironlake_dual_lvds_100m; @@ -543,11 +490,10 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc, static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; const intel_limit_t *limit; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { - if (is_dual_link_lvds(dev_priv, LVDS)) + if (intel_is_dual_link_lvds(dev)) /* LVDS with dual channel */ limit = &intel_limits_g4x_dual_channel_lvds; else @@ -679,19 +625,16 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; intel_clock_t clock; int err = target; - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && - (I915_READ(LVDS)) != 0) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { /* - * For LVDS, if the panel is on, just rely on its current - * settings for dual-channel. We haven't figured out how to - * reliably set up different single/dual channel state, if we - * even can. + * For LVDS just rely on its current settings for dual-channel. + * We haven't figured out how to reliably set up different + * single/dual channel state, if we even can. */ - if (is_dual_link_lvds(dev_priv, LVDS)) + if (intel_is_dual_link_lvds(dev)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -744,7 +687,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, intel_clock_t *best_clock) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; intel_clock_t clock; int max_n; bool found; @@ -759,8 +701,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, lvds_reg = PCH_LVDS; else lvds_reg = LVDS; - if ((I915_READ(lvds_reg) & LVDS_CLKB_POWER_MASK) == - LVDS_CLKB_POWER_UP) + if (intel_is_dual_link_lvds(dev)) clock.p2 = limit->p2.p2_fast; else clock.p2 = limit->p2.p2_slow; @@ -1041,6 +982,51 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe) } } +/* + * ibx_digital_port_connected - is the specified port connected? + * @dev_priv: i915 private structure + * @port: the port to test + * + * Returns true if @port is connected, false otherwise. + */ +bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *port) +{ + u32 bit; + + if (HAS_PCH_IBX(dev_priv->dev)) { + switch(port->port) { + case PORT_B: + bit = SDE_PORTB_HOTPLUG; + break; + case PORT_C: + bit = SDE_PORTC_HOTPLUG; + break; + case PORT_D: + bit = SDE_PORTD_HOTPLUG; + break; + default: + return true; + } + } else { + switch(port->port) { + case PORT_B: + bit = SDE_PORTB_HOTPLUG_CPT; + break; + case PORT_C: + bit = SDE_PORTC_HOTPLUG_CPT; + break; + case PORT_D: + bit = SDE_PORTD_HOTPLUG_CPT; + break; + default: + return true; + } + } + + return I915_READ(SDEISR) & bit; +} + static const char *state_string(bool enabled) { return enabled ? "on" : "off"; @@ -1119,8 +1105,8 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); - if (IS_HASWELL(dev_priv->dev)) { - /* On Haswell, DDI is used instead of FDI_TX_CTL */ + if (HAS_DDI(dev_priv->dev)) { + /* DDI does not have a specific FDI_TX register */ reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); val = I915_READ(reg); cur_state = !!(val & TRANS_DDI_FUNC_ENABLE); @@ -1164,7 +1150,7 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv, return; /* On Haswell, DDI ports are responsible for the FDI PLL setup */ - if (IS_HASWELL(dev_priv->dev)) + if (HAS_DDI(dev_priv->dev)) return; reg = FDI_TX_CTL(pipe); @@ -1225,9 +1211,15 @@ void assert_pipe(struct drm_i915_private *dev_priv, if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE) state = true; - reg = PIPECONF(cpu_transcoder); - val = I915_READ(reg); - cur_state = !!(val & PIPECONF_ENABLE); + if (IS_HASWELL(dev_priv->dev) && cpu_transcoder != TRANSCODER_EDP && + !(I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE)) { + cur_state = false; + } else { + reg = PIPECONF(cpu_transcoder); + val = I915_READ(reg); + cur_state = !!(val & PIPECONF_ENABLE); + } + WARN(cur_state != state, "pipe %c assertion failure (expected %s, current %s)\n", pipe_name(pipe), state_string(state), state_string(cur_state)); @@ -1505,10 +1497,11 @@ intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, { u32 tmp; - spin_lock(&dev_priv->dpio_lock); + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to become ready\n"); - goto out_unlock; + return; } I915_WRITE(SBI_ADDR, (reg << 16)); @@ -1523,11 +1516,8 @@ intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to complete write transaction\n"); - goto out_unlock; + return; } - -out_unlock: - spin_unlock(&dev_priv->dpio_lock); } static u32 @@ -1536,10 +1526,11 @@ intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, { u32 value = 0; - spin_lock(&dev_priv->dpio_lock); + WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock)); + if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to become ready\n"); - goto out_unlock; + return 0; } I915_WRITE(SBI_ADDR, (reg << 16)); @@ -1553,14 +1544,10 @@ intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0, 100)) { DRM_ERROR("timeout waiting for SBI to complete read transaction\n"); - goto out_unlock; + return 0; } - value = I915_READ(SBI_DATA); - -out_unlock: - spin_unlock(&dev_priv->dpio_lock); - return value; + return I915_READ(SBI_DATA); } /** @@ -1692,8 +1679,8 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, * make the BPC in transcoder be consistent with * that in pipeconf reg. */ - val &= ~PIPE_BPC_MASK; - val |= pipeconf_val & PIPE_BPC_MASK; + val &= ~PIPECONF_BPC_MASK; + val |= pipeconf_val & PIPECONF_BPC_MASK; } val &= ~TRANS_INTERLACE_MASK; @@ -1720,7 +1707,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv, BUG_ON(dev_priv->info->gen < 5); /* FDI must be feeding us bits for PCH ports */ - assert_fdi_tx_enabled(dev_priv, cpu_transcoder); + assert_fdi_tx_enabled(dev_priv, (enum i915_pipe) cpu_transcoder); assert_fdi_rx_enabled(dev_priv, TRANSCODER_A); /* Workaround: set timing override bit. */ @@ -1808,11 +1795,11 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum i915_pipe { enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, pipe); - enum transcoder pch_transcoder; + enum i915_pipe pch_transcoder; int reg; u32 val; - if (IS_HASWELL(dev_priv->dev)) + if (HAS_PCH_LPT(dev_priv->dev)) pch_transcoder = TRANSCODER_A; else pch_transcoder = pipe; @@ -1828,7 +1815,8 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum i915_pipe if (pch_port) { /* if driving the PCH, we need FDI enabled */ assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder); - assert_fdi_tx_pll_enabled(dev_priv, cpu_transcoder); + assert_fdi_tx_pll_enabled(dev_priv, + (enum i915_pipe) cpu_transcoder); } /* FIXME: assert CPU port conditions for SNB+ */ } @@ -2245,10 +2233,6 @@ intel_finish_fb(struct drm_framebuffer *old_fb) bool was_interruptible = dev_priv->mm.interruptible; int ret; - wait_event(dev_priv->pending_flip_queue, - atomic_read(&dev_priv->mm.wedged) || - atomic_read(&obj->pending_flip) == 0); - /* Big Hammer, we also need to ensure that any pending * MI_WAIT_FOR_EVENT inside a user batch buffer on the * current scanout is retired before unpinning the old @@ -2333,12 +2317,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return -EINVAL; } - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, to_intel_framebuffer(fb)->obj, NULL); if (ret != 0) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); DRM_ERROR("pin & fence failed\n"); return ret; } @@ -2349,7 +2333,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, ret = dev_priv->display.update_plane(crtc, fb, x, y); if (ret) { intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); DRM_ERROR("failed to update base address\n"); return ret; } @@ -2365,50 +2349,13 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } intel_update_fbc(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); intel_crtc_update_sarea_pos(crtc, x, y); return 0; } -static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock); - dpa_ctl = I915_READ(DP_A); - dpa_ctl &= ~DP_PLL_FREQ_MASK; - - if (clock < 200000) { - u32 temp; - dpa_ctl |= DP_PLL_FREQ_160MHZ; - /* workaround for 160Mhz: - 1) program 0x4600c bits 15:0 = 0x8124 - 2) program 0x46010 bit 0 = 1 - 3) program 0x46034 bit 24 = 1 - 4) program 0x64000 bit 14 = 1 - */ - temp = I915_READ(0x4600c); - temp &= 0xffff0000; - I915_WRITE(0x4600c, temp | 0x8124); - - temp = I915_READ(0x46010); - I915_WRITE(0x46010, temp | 1); - - temp = I915_READ(0x46034); - I915_WRITE(0x46034, temp | (1 << 24)); - } else { - dpa_ctl |= DP_PLL_FREQ_270MHZ; - } - I915_WRITE(DP_A, dpa_ctl); - - POSTING_READ(DP_A); - udelay(500); -} - static void intel_fdi_normal_train(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2837,7 +2784,7 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) temp = I915_READ(reg); temp &= ~((0x7 << 19) | (0x7 << 16)); temp |= (intel_crtc->fdi_lanes - 1) << 19; - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE); POSTING_READ(reg); @@ -2850,18 +2797,14 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) POSTING_READ(reg); udelay(200); - /* On Haswell, the PLL configuration for ports and pipes is handled - * separately, as part of DDI setup */ - if (!IS_HASWELL(dev)) { - /* Enable CPU FDI TX PLL, always on for Ironlake */ - reg = FDI_TX_CTL(pipe); - temp = I915_READ(reg); - if ((temp & FDI_TX_PLL_ENABLE) == 0) { - I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); + /* Enable CPU FDI TX PLL, always on for Ironlake */ + reg = FDI_TX_CTL(pipe); + temp = I915_READ(reg); + if ((temp & FDI_TX_PLL_ENABLE) == 0) { + I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE); - POSTING_READ(reg); - udelay(100); - } + POSTING_READ(reg); + udelay(100); } } @@ -2911,7 +2854,7 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) reg = FDI_RX_CTL(pipe); temp = I915_READ(reg); temp &= ~(0x7 << 16); - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp & ~FDI_RX_ENABLE); POSTING_READ(reg); @@ -2940,7 +2883,7 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) } /* BPC in FDI rx is consistent with that in PIPECONF */ temp &= ~(0x07 << 16); - temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11; + temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11; I915_WRITE(reg, temp); POSTING_READ(reg); @@ -2951,9 +2894,11 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); bool pending; - if (atomic_read(&dev_priv->mm.wedged)) + if (i915_reset_in_progress(&dev_priv->gpu_error) || + intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) return false; lockmgr(&dev->event_lock, LK_EXCLUSIVE); @@ -2971,12 +2916,14 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) if (crtc->fb == NULL) return; + WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); + wait_event(dev_priv->pending_flip_queue, !intel_crtc_has_pending_flip(crtc)); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_finish_fb(crtc->fb); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } static bool ironlake_crtc_driving_pch(struct drm_crtc *crtc) @@ -3013,6 +2960,8 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) u32 divsel, phaseinc, auxdiv, phasedir = 0; u32 temp; + mutex_lock(&dev_priv->dpio_lock); + /* It is necessary to ungate the pixclk gate prior to programming * the divisors, and gate it back when it is done. */ @@ -3087,6 +3036,8 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) udelay(24); I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE); + + mutex_unlock(&dev_priv->dpio_lock); } /* @@ -3167,7 +3118,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) if (HAS_PCH_CPT(dev) && (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { - u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) >> 5; + u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); temp &= ~(TRANS_DP_PORT_SEL_MASK | @@ -3397,9 +3348,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (is_pch_port) ironlake_pch_enable(crtc); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); intel_crtc_update_cursor(crtc, true); @@ -3477,9 +3428,9 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) if (is_pch_port) lpt_pch_enable(crtc); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); intel_crtc_update_cursor(crtc, true); @@ -3572,9 +3523,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) intel_crtc->active = false; intel_update_watermarks(dev); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -3627,9 +3578,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_crtc->active = false; intel_update_watermarks(dev); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } static void ironlake_crtc_off(struct drm_crtc *crtc) @@ -3644,7 +3595,7 @@ static void haswell_crtc_off(struct drm_crtc *crtc) /* Stop saying we're using TRANSCODER_EDP because some other CRTC might * start using it. */ - intel_crtc->cpu_transcoder = intel_crtc->pipe; + intel_crtc->cpu_transcoder = (enum transcoder) intel_crtc->pipe; intel_ddi_put_crtc_pll(crtc); } @@ -3655,11 +3606,11 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); dev_priv->mm.interruptible = false; (void) intel_overlay_switch_off(intel_crtc->overlay); dev_priv->mm.interruptible = true; - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } /* Let userspace switch the overlay on again. In most cases userspace @@ -3667,6 +3618,30 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable) */ } +/** + * i9xx_fixup_plane - ugly workaround for G45 to fire up the hardware + * cursor plane briefly if not already running after enabling the display + * plane. + * This workaround avoids occasional blank screens when self refresh is + * enabled. + */ +static void +g4x_fixup_plane(struct drm_i915_private *dev_priv, enum i915_pipe pipe) +{ + u32 cntl = I915_READ(CURCNTR(pipe)); + + if ((cntl & CURSOR_MODE) == 0) { + u32 fw_bcl_self = I915_READ(FW_BLC_SELF); + + I915_WRITE(FW_BLC_SELF, fw_bcl_self & ~FW_BLC_SELF_EN); + I915_WRITE(CURCNTR(pipe), CURSOR_MODE_64_ARGB_AX); + intel_wait_for_vblank(dev_priv->dev, pipe); + I915_WRITE(CURCNTR(pipe), cntl); + I915_WRITE(CURBASE(pipe), I915_READ(CURBASE(pipe))); + I915_WRITE(FW_BLC_SELF, fw_bcl_self); + } +} + static void i9xx_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3685,8 +3660,15 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) intel_update_watermarks(dev); intel_enable_pll(dev_priv, pipe); + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_enable) + encoder->pre_enable(encoder); + intel_enable_pipe(dev_priv, pipe, false); intel_enable_plane(dev_priv, plane, pipe); + if (IS_G4X(dev)) + g4x_fixup_plane(dev_priv, pipe); intel_crtc_load_lut(crtc); intel_update_fbc(dev); @@ -3823,10 +3805,12 @@ static void intel_crtc_disable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_connector *connector; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->enabled); + intel_crtc->eld_vld = false; dev_priv->display.crtc_disable(crtc); intel_crtc_update_sarea(crtc, false); dev_priv->display.off(crtc); @@ -3835,9 +3819,9 @@ static void intel_crtc_disable(struct drm_crtc *crtc) assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); if (crtc->fb) { - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); crtc->fb = NULL; } @@ -4059,16 +4043,8 @@ static int i830_get_display_clock_speed(struct drm_device *dev) return 133000; } -struct fdi_m_n { - u32 tu; - u32 gmch_m; - u32 gmch_n; - u32 link_m; - u32 link_n; -}; - static void -fdi_reduce_ratio(u32 *num, u32 *den) +intel_reduce_ratio(uint32_t *num, uint32_t *den) { while (*num > 0xffffff || *den > 0xffffff) { *num >>= 1; @@ -4076,20 +4052,18 @@ fdi_reduce_ratio(u32 *num, u32 *den) } } -static void -ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock, - int link_clock, struct fdi_m_n *m_n) +void +intel_link_compute_m_n(int bits_per_pixel, int nlanes, + int pixel_clock, int link_clock, + struct intel_link_m_n *m_n) { - m_n->tu = 64; /* default size */ - - /* BUG_ON(pixel_clock > INT_MAX / 36); */ + m_n->tu = 64; m_n->gmch_m = bits_per_pixel * pixel_clock; m_n->gmch_n = link_clock * nlanes * 8; - fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - + intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); m_n->link_m = pixel_clock; m_n->link_n = link_clock; - fdi_reduce_ratio(&m_n->link_m, &m_n->link_n); + intel_reduce_ratio(&m_n->link_m, &m_n->link_n); } static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) @@ -4336,51 +4310,6 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc, } } -static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock, - struct drm_display_mode *adjusted_mode) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - u32 temp; - - temp = I915_READ(LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (pipe == 1) { - temp |= LVDS_PIPEB_SELECT; - } else { - temp &= ~LVDS_PIPEB_SELECT; - } - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock->p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - /* set the dithering flag on LVDS as needed */ - if (INTEL_INFO(dev)->gen >= 4) { - if (dev_priv->lvds_dither) - temp |= LVDS_ENABLE_DITHER; - else - temp &= ~LVDS_ENABLE_DITHER; - } - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(LVDS, temp); -} - static void vlv_update_pll(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -4396,6 +4325,8 @@ static void vlv_update_pll(struct drm_crtc *crtc, bool is_sdvo; u32 temp; + lockmgr(&dev_priv->dpio_lock, LK_EXCLUSIVE); + is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) || intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI); @@ -4479,6 +4410,8 @@ static void vlv_update_pll(struct drm_crtc *crtc, temp |= (1 << 21); intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp); } + + lockmgr(&dev_priv->dpio_lock, LK_RELEASE); } static void i9xx_update_pll(struct drm_crtc *crtc, @@ -4490,6 +4423,7 @@ static void i9xx_update_pll(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; u32 dpll; bool is_sdvo; @@ -4558,12 +4492,9 @@ static void i9xx_update_pll(struct drm_crtc *crtc, POSTING_READ(DPLL(pipe)); udelay(150); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - intel_update_lvds(crtc, clock, adjusted_mode); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) intel_dp_set_m_n(crtc, mode, adjusted_mode); @@ -4602,6 +4533,7 @@ static void i8xx_update_pll(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_encoder *encoder; int pipe = intel_crtc->pipe; u32 dpll; @@ -4635,12 +4567,9 @@ static void i8xx_update_pll(struct drm_crtc *crtc, POSTING_READ(DPLL(pipe)); udelay(150); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) - intel_update_lvds(crtc, clock, adjusted_mode); + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); I915_WRITE(DPLL(pipe), dpll); @@ -4830,10 +4759,10 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, } /* default to 8bpc */ - pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN); + pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN); if (is_dp) { if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - pipeconf |= PIPECONF_BPP_6 | + pipeconf |= PIPECONF_6BPC | PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP; } @@ -4841,7 +4770,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) { if (adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { - pipeconf |= PIPECONF_BPP_6 | + pipeconf |= PIPECONF_6BPC | PIPECONF_ENABLE | I965_PIPECONF_ACTIVE; } @@ -5028,6 +4957,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) if (!has_vga) return; + mutex_lock(&dev_priv->dpio_lock); + /* XXX: Rip out SDV support once Haswell ships for real. */ if (IS_HASWELL(dev) && (dev->pci_device & 0xFF00) == 0x0C00) is_sdv = true; @@ -5170,6 +5101,8 @@ static void lpt_init_pch_refclk(struct drm_device *dev) tmp = intel_sbi_read(dev_priv, SBI_DBUFF0, SBI_ICLK); tmp |= SBI_DBUFF0_ENABLE; intel_sbi_write(dev_priv, SBI_DBUFF0, tmp, SBI_ICLK); + + mutex_unlock(&dev_priv->dpio_lock); } /* @@ -5224,19 +5157,19 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, val = I915_READ(PIPECONF(pipe)); - val &= ~PIPE_BPC_MASK; + val &= ~PIPECONF_BPC_MASK; switch (intel_crtc->bpp) { case 18: - val |= PIPE_6BPC; + val |= PIPECONF_6BPC; break; case 24: - val |= PIPE_8BPC; + val |= PIPECONF_8BPC; break; case 30: - val |= PIPE_10BPC; + val |= PIPECONF_10BPC; break; case 36: - val |= PIPE_12BPC; + val |= PIPECONF_12BPC; break; default: /* Case prevented by intel_choose_pipe_bpp_dither. */ @@ -5253,10 +5186,80 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc, else val |= PIPECONF_PROGRESSIVE; + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + val |= PIPECONF_COLOR_RANGE_SELECT; + else + val &= ~PIPECONF_COLOR_RANGE_SELECT; + I915_WRITE(PIPECONF(pipe), val); POSTING_READ(PIPECONF(pipe)); } +/* + * Set up the pipe CSC unit. + * + * Currently only full range RGB to limited range RGB conversion + * is supported, but eventually this should handle various + * RGB<->YCbCr scenarios as well. + */ +static void intel_set_pipe_csc(struct drm_crtc *crtc, + const struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + uint16_t coeff = 0x7800; /* 1.0 */ + + /* + * TODO: Check what kind of values actually come out of the pipe + * with these coeff/postoff values and adjust to get the best + * accuracy. Perhaps we even need to take the bpc value into + * consideration. + */ + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */ + + /* + * GY/GU and RY/RU should be the other way around according + * to BSpec, but reality doesn't agree. Just set them up in + * a way that results in the correct picture. + */ + I915_WRITE(PIPE_CSC_COEFF_RY_GY(pipe), coeff << 16); + I915_WRITE(PIPE_CSC_COEFF_BY(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RU_GU(pipe), coeff); + I915_WRITE(PIPE_CSC_COEFF_BU(pipe), 0); + + I915_WRITE(PIPE_CSC_COEFF_RV_GV(pipe), 0); + I915_WRITE(PIPE_CSC_COEFF_BV(pipe), coeff << 16); + + I915_WRITE(PIPE_CSC_PREOFF_HI(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_ME(pipe), 0); + I915_WRITE(PIPE_CSC_PREOFF_LO(pipe), 0); + + if (INTEL_INFO(dev)->gen > 6) { + uint16_t postoff = 0; + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + postoff = (16 * (1 << 13) / 255) & 0x1fff; + + I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_ME(pipe), postoff); + I915_WRITE(PIPE_CSC_POSTOFF_LO(pipe), postoff); + + I915_WRITE(PIPE_CSC_MODE(pipe), 0); + } else { + uint32_t mode = CSC_MODE_YUV_TO_RGB; + + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + mode |= CSC_BLACK_SCREEN_OFFSET; + + I915_WRITE(PIPE_CSC_MODE(pipe), mode); + } +} + static void haswell_set_pipeconf(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode, bool dither) @@ -5447,7 +5450,7 @@ static void ironlake_set_m_n(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; struct intel_encoder *intel_encoder, *edp_encoder = NULL; - struct fdi_m_n m_n = {0}; + struct intel_link_m_n m_n = {0}; int target_clock, pixel_multiplier, lane, link_bw; bool is_dp = false, is_cpu_edp = false; @@ -5499,8 +5502,7 @@ static void ironlake_set_m_n(struct drm_crtc *crtc, if (pixel_multiplier > 1) link_bw *= pixel_multiplier; - ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, - &m_n); + intel_link_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw, &m_n); I915_WRITE(PIPE_DATA_M1(cpu_transcoder), TU_SIZE(m_n.tu) | m_n.gmch_m); I915_WRITE(PIPE_DATA_N1(cpu_transcoder), m_n.gmch_n); @@ -5553,7 +5555,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && dev_priv->lvds_ssc_freq == 100) || - (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP) + intel_is_dual_link_lvds(dev)) factor = 25; } else if (is_sdvo && is_tv) factor = 20; @@ -5628,7 +5630,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, bool ok, has_reduced_clock = false; bool is_lvds = false, is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; - u32 temp; int ret; bool dither, fdi_config_ok; @@ -5692,54 +5693,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else intel_put_pch_pll(intel_crtc); - /* The LVDS pin pair needs to be on before the DPLLs are enabled. - * This is an exception to the general rule that mode_set doesn't turn - * things on. - */ - if (is_lvds) { - temp = I915_READ(PCH_LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (HAS_PCH_CPT(dev)) { - temp &= ~PORT_TRANS_SEL_MASK; - temp |= PORT_TRANS_SEL_CPT(pipe); - } else { - if (pipe == 1) - temp |= LVDS_PIPEB_SELECT; - else - temp &= ~LVDS_PIPEB_SELECT; - } - - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether we're going to - * set the DPLLs for dual-channel mode or not. - */ - if (clock.p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) - * appropriately here, but we need to look more thoroughly into how - * panels behave in the two modes. - */ - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(PCH_LVDS, temp); - } - - if (is_dp && !is_cpu_edp) { + if (is_dp && !is_cpu_edp) intel_dp_set_m_n(crtc, mode, adjusted_mode); - } else { - /* For non-DP output, clear any trans DP clock recovery setting.*/ - I915_WRITE(TRANSDATA_M1(pipe), 0); - I915_WRITE(TRANSDATA_N1(pipe), 0); - I915_WRITE(TRANSDPLINK_M1(pipe), 0); - I915_WRITE(TRANSDPLINK_N1(pipe), 0); - } + + for_each_encoder_on_crtc(dev, crtc, encoder) + if (encoder->pre_pll_enable) + encoder->pre_pll_enable(encoder); if (intel_crtc->pch_pll) { I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); @@ -5775,9 +5734,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc); - if (is_cpu_edp) - ironlake_set_pll_edp(crtc, adjusted_mode->clock); - ironlake_set_pipeconf(crtc, adjusted_mode, dither); intel_wait_for_vblank(dev, pipe); @@ -5795,6 +5751,35 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, return fdi_config_ok ? ret : -EINVAL; } +static void haswell_modeset_global_resources(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = false; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { + if (crtc->pipe != PIPE_A && crtc->base.enabled) + enable = true; + /* XXX: Should check for edp transcoder here, but thanks to init + * sequence that's not yet available. Just in case desktop eDP + * on PORT D is possible on haswell, too. */ + } + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->type != INTEL_OUTPUT_EDP && + encoder->connectors_active) + enable = true; + } + + /* Even the eDP panel fitter is outside the always-on well. */ + if (dev_priv->pch_pf_size) + enable = true; + + intel_set_power_well(dev, enable); +} + static int haswell_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, @@ -5807,20 +5792,13 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int pipe = intel_crtc->pipe; int plane = intel_crtc->plane; int num_connectors = 0; - intel_clock_t clock, reduced_clock; - u32 dpll = 0, fp = 0, fp2 = 0; - bool ok, has_reduced_clock = false; - bool is_lvds = false, is_dp = false, is_cpu_edp = false; + bool is_dp = false, is_cpu_edp = false; struct intel_encoder *encoder; - u32 temp; int ret; bool dither; for_each_encoder_on_crtc(dev, crtc, encoder) { switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; case INTEL_OUTPUT_DISPLAYPORT: is_dp = true; break; @@ -5854,147 +5832,32 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock)) return -EINVAL; - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock, - &has_reduced_clock, - &reduced_clock); - if (!ok) { - DRM_ERROR("Couldn't find PLL settings for mode!\n"); - return -EINVAL; - } - } - /* Ensure that the cursor is valid for the new mode before changing... */ intel_crtc_update_cursor(crtc, true); /* determine panel color depth */ dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, adjusted_mode); - if (is_lvds && dev_priv->lvds_dither) - dither = true; DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe); drm_mode_debug_printmodeline(mode); - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - fp = clock.n << 16 | clock.m1 << 8 | clock.m2; - if (has_reduced_clock) - fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 | - reduced_clock.m2; - - dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, - fp); - - /* CPU eDP is the only output that doesn't need a PCH PLL of its - * own on pre-Haswell/LPT generation */ - if (!is_cpu_edp) { - struct intel_pch_pll *pll; - - pll = intel_get_pch_pll(intel_crtc, dpll, fp); - if (pll == NULL) { - DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n", - pipe); - return -EINVAL; - } - } else - intel_put_pch_pll(intel_crtc); - - /* The LVDS pin pair needs to be on before the DPLLs are - * enabled. This is an exception to the general rule that - * mode_set doesn't turn things on. - */ - if (is_lvds) { - temp = I915_READ(PCH_LVDS); - temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; - if (HAS_PCH_CPT(dev)) { - temp &= ~PORT_TRANS_SEL_MASK; - temp |= PORT_TRANS_SEL_CPT(pipe); - } else { - if (pipe == 1) - temp |= LVDS_PIPEB_SELECT; - else - temp &= ~LVDS_PIPEB_SELECT; - } - - /* set the corresponsding LVDS_BORDER bit */ - temp |= dev_priv->lvds_border_bits; - /* Set the B0-B3 data pairs corresponding to whether - * we're going to set the DPLLs for dual-channel mode or - * not. - */ - if (clock.p2 == 7) - temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; - else - temp &= ~(LVDS_B0B3_POWER_UP | - LVDS_CLKB_POWER_UP); - - /* It would be nice to set 24 vs 18-bit mode - * (LVDS_A3_POWER_UP) appropriately here, but we need to - * look more thoroughly into how panels behave in the - * two modes. - */ - temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); - if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) - temp |= LVDS_HSYNC_POLARITY; - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - temp |= LVDS_VSYNC_POLARITY; - I915_WRITE(PCH_LVDS, temp); - } - } - - if (is_dp && !is_cpu_edp) { + if (is_dp && !is_cpu_edp) intel_dp_set_m_n(crtc, mode, adjusted_mode); - } else { - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - /* For non-DP output, clear any trans DP clock recovery - * setting.*/ - I915_WRITE(TRANSDATA_M1(pipe), 0); - I915_WRITE(TRANSDATA_N1(pipe), 0); - I915_WRITE(TRANSDPLINK_M1(pipe), 0); - I915_WRITE(TRANSDPLINK_N1(pipe), 0); - } - } intel_crtc->lowfreq_avail = false; - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { - if (intel_crtc->pch_pll) { - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); - - /* Wait for the clocks to stabilize. */ - POSTING_READ(intel_crtc->pch_pll->pll_reg); - udelay(150); - - /* The pixel multiplier can only be updated once the - * DPLL is enabled and the clocks are stable. - * - * So write it again. - */ - I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll); - } - - if (intel_crtc->pch_pll) { - if (is_lvds && has_reduced_clock && i915_powersave) { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2); - intel_crtc->lowfreq_avail = true; - } else { - I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp); - } - } - } intel_set_pipe_timings(intel_crtc, mode, adjusted_mode); if (!is_dp || is_cpu_edp) ironlake_set_m_n(crtc, mode, adjusted_mode); - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) - if (is_cpu_edp) - ironlake_set_pll_edp(crtc, adjusted_mode->clock); - haswell_set_pipeconf(crtc, adjusted_mode, dither); + intel_set_pipe_csc(crtc, adjusted_mode); + /* Set up the display plane register */ - I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE); + I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE); POSTING_READ(DSPCNTR(plane)); ret = intel_pipe_set_base(crtc, x, y, fb); @@ -6116,6 +5979,7 @@ static void haswell_write_eld(struct drm_connector *connector, struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t eldv; uint32_t i; int len; @@ -6157,6 +6021,7 @@ static void haswell_write_eld(struct drm_connector *connector, DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(pipe)); eldv = AUDIO_ELD_VALID_A << (pipe * 4); + intel_crtc->eld_vld = true; if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n"); @@ -6392,6 +6257,8 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base) cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); cntl |= CURSOR_MODE_DISABLE; } + if (IS_HASWELL(dev)) + cntl |= CURSOR_PIPE_CSC_ENABLE; I915_WRITE(CURCNTR_IVB(pipe), cntl); intel_crtc->cursor_visible = visible; @@ -6476,7 +6343,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, DRM_DEBUG_KMS("cursor off\n"); addr = 0; obj = NULL; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); goto finish; } @@ -6497,7 +6364,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, } /* we only need to pin inside GTT if cursor is non-phy */ - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); if (!dev_priv->info->cursor_needs_physical) { if (obj->tiling_mode) { DRM_ERROR("cursor cannot be tiled\n"); @@ -6543,7 +6410,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, drm_gem_object_unreference(&intel_crtc->cursor_bo->base); } - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; @@ -6556,7 +6423,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, fail_unpin: i915_gem_object_unpin(obj); fail_locked: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); fail: drm_gem_object_unreference_unlocked(&obj->base); return ret; @@ -6657,15 +6524,15 @@ intel_framebuffer_create(struct drm_device *dev, static u32 intel_framebuffer_pitch_for_width(int width, int bpp) { - u32 pitch = howmany(width * bpp, 8); - return roundup2(pitch, 64); + u32 pitch = DIV_ROUND_UP(width * bpp, 8); + return ALIGN(pitch, 64); } static u32 intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp) { u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp); - return roundup2(pitch * mode->vdisplay, PAGE_SIZE); + return ALIGN(pitch * mode->vdisplay, PAGE_SIZE); } static struct drm_framebuffer * @@ -6748,6 +6615,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, if (encoder->crtc) { crtc = encoder->crtc; + mutex_lock(&crtc->mutex); + old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -6777,6 +6646,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, return false; } + mutex_lock(&crtc->mutex); intel_encoder->new_crtc = to_intel_crtc(crtc); to_intel_connector(connector)->new_encoder = intel_encoder; @@ -6804,19 +6674,20 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n"); if (IS_ERR(fb)) { DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n"); + mutex_unlock(&crtc->mutex); return false; } - if (!intel_set_mode(crtc, mode, 0, 0, fb)) { + if (intel_set_mode(crtc, mode, 0, 0, fb)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); + mutex_unlock(&crtc->mutex); return false; } /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev, intel_crtc->pipe); - return true; } @@ -6826,27 +6697,31 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_encoder *intel_encoder = intel_attached_encoder(connector); struct drm_encoder *encoder = &intel_encoder->base; + struct drm_crtc *crtc = encoder->crtc; DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n", connector->base.id, drm_get_connector_name(connector), encoder->base.id, drm_get_encoder_name(encoder)); if (old->load_detect_temp) { - struct drm_crtc *crtc = encoder->crtc; - to_intel_connector(connector)->new_encoder = NULL; intel_encoder->new_crtc = NULL; intel_set_mode(crtc, NULL, 0, 0, NULL); - if (old->release_fb) - old->release_fb->funcs->destroy(old->release_fb); + if (old->release_fb) { + drm_framebuffer_unregister_private(old->release_fb); + drm_framebuffer_unreference(old->release_fb); + } + mutex_unlock(&crtc->mutex); return; } /* Switch crtc and encoder back off if necessary */ if (old->dpms_mode != DRM_MODE_DPMS_ON) connector->funcs->dpms(connector, old->dpms_mode); + + mutex_unlock(&crtc->mutex); } /* Returns the clock of the currently programmed mode of the given pipe. */ @@ -7098,13 +6973,13 @@ static void intel_unpin_work_fn(struct work_struct *__work) container_of(__work, struct intel_unpin_work, work); struct drm_device *dev = work->crtc->dev; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(work->old_fb_obj); drm_gem_object_unreference(&work->pending_flip_obj->base); drm_gem_object_unreference(&work->old_fb_obj->base); intel_update_fbc(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0); atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count); @@ -7149,9 +7024,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev, obj = work->old_fb_obj; - atomic_clear_mask(1 << intel_crtc->plane, - &obj->pending_flip.counter); - wake_up(&dev_priv->pending_flip_queue); + wake_up_all(&dev_priv->pending_flip_queue); queue_work(dev_priv->wq, &work->work); } @@ -7191,11 +7064,11 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane) inline static void intel_mark_page_flip_active(struct intel_crtc *intel_crtc) { /* Ensure that the work item is consistent when activating it ... */ - cpu_ccfence(); + cpu_sfence(); atomic_set(&intel_crtc->unpin_work->pending, INTEL_FLIP_PENDING); /* and that it is marked active as soon as the irq could fire. */ - cpu_ccfence(); - } + cpu_sfence(); +} static int intel_gen2_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, @@ -7506,11 +7379,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->enable_stall_check = true; - /* Block clients from rendering to the new back buffer until - * the flip occurs and the object is no longer visible. - */ - atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); atomic_inc(&intel_crtc->unpin_work_count); + intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); ret = dev_priv->display.queue_flip(dev, crtc, fb, obj); if (ret) @@ -7518,17 +7388,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_disable_fbc(dev); intel_mark_fb_busy(obj); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); return 0; cleanup_pending: atomic_dec(&intel_crtc->unpin_work_count); crtc->fb = old_fb; - atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); drm_gem_object_unreference(&work->old_fb_obj->base); drm_gem_object_unreference(&obj->base); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); cleanup: lockmgr(&dev->event_lock, LK_EXCLUSIVE); @@ -7578,13 +7447,11 @@ static bool intel_encoder_crtc_ok(struct drm_encoder *encoder, int crtc_mask = 1; WARN(!crtc, "checking null crtc?\n"); - /* profmakx: this is to prevent the kernel from panicing - */ + /* profmakx: this is to prevent the kernel from panicing */ if(!crtc) { return false; } - dev = crtc->dev; list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { @@ -7944,16 +7811,21 @@ intel_modeset_check_state(struct drm_device *dev) } } -bool intel_set_mode(struct drm_crtc *crtc, - struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *fb) +static int __intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) { struct drm_device *dev = crtc->dev; drm_i915_private_t *dev_priv = dev->dev_private; - struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; + struct drm_display_mode *adjusted_mode, *saved_mode, *saved_hwmode; struct intel_crtc *intel_crtc; unsigned disable_pipes, prepare_pipes, modeset_pipes; - bool ret = true; + int ret = 0; + + saved_mode = kmalloc(2 * sizeof(*saved_mode), M_DRM, M_WAITOK); + if (!saved_mode) + return -ENOMEM; + saved_hwmode = saved_mode + 1; intel_modeset_affected_pipes(crtc, &modeset_pipes, &prepare_pipes, &disable_pipes); @@ -7964,8 +7836,8 @@ bool intel_set_mode(struct drm_crtc *crtc, for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc) intel_crtc_disable(&intel_crtc->base); - saved_hwmode = crtc->hwmode; - saved_mode = crtc->mode; + *saved_hwmode = crtc->hwmode; + *saved_mode = crtc->mode; /* Hack: Because we don't (yet) support global modeset on multiple * crtcs, we don't keep track of the new mode for more than one crtc. @@ -7976,7 +7848,8 @@ bool intel_set_mode(struct drm_crtc *crtc, if (modeset_pipes) { adjusted_mode = intel_modeset_adjusted_mode(crtc, mode); if (IS_ERR(adjusted_mode)) { - return false; + ret = PTR_ERR(adjusted_mode); + goto out; } } @@ -8002,11 +7875,11 @@ bool intel_set_mode(struct drm_crtc *crtc, * on the DPLL. */ for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) { - ret = !intel_crtc_mode_set(&intel_crtc->base, - mode, adjusted_mode, - x, y, fb); - if (!ret) - goto done; + ret = intel_crtc_mode_set(&intel_crtc->base, + mode, adjusted_mode, + x, y, fb); + if (ret) + goto done; } /* Now enable the clocks, plane, pipe, and connectors that we set up. */ @@ -8027,16 +7900,35 @@ bool intel_set_mode(struct drm_crtc *crtc, /* FIXME: add subpixel order */ done: drm_mode_destroy(dev, adjusted_mode); - if (!ret && crtc->enabled) { - crtc->hwmode = saved_hwmode; - crtc->mode = saved_mode; - } else { - intel_modeset_check_state(dev); + if (ret && crtc->enabled) { + crtc->hwmode = *saved_hwmode; + crtc->mode = *saved_mode; } +out: + kfree(saved_mode, M_DRM); + return ret; +} + +int intel_set_mode(struct drm_crtc *crtc, + struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *fb) +{ + int ret; + + ret = __intel_set_mode(crtc, mode, x, y, fb); + + if (ret == 0) + intel_modeset_check_state(crtc->dev); + return ret; } +void intel_crtc_restore_mode(struct drm_crtc *crtc) +{ + intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); +} + #undef for_each_intel_crtc_masked static void intel_set_config_free(struct intel_set_config *config) @@ -8105,6 +7997,21 @@ static void intel_set_config_restore_state(struct drm_device *dev, } } +static bool +is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors, + int num_connectors) +{ + int i; + + for (i = 0; i < num_connectors; i++) + if (connectors[i].encoder && + connectors[i].encoder->crtc == crtc && + connectors[i].dpms != DRM_MODE_DPMS_ON) + return true; + + return false; +} + static void intel_set_config_compute_mode_changes(struct drm_mode_set *set, struct intel_set_config *config) @@ -8112,7 +8019,11 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) { + if (set->connectors != NULL && + is_crtc_connector_off(set->crtc, *set->connectors, + set->num_connectors)) { + config->mode_changed = true; + } else if (set->crtc->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ if (set->crtc->fb == NULL) { DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); @@ -8124,8 +8035,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, } else if (set->fb->bits_per_pixel != set->crtc->fb->bits_per_pixel) { config->mode_changed = true; - } else + } else { config->fb_changed = true; + } } if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y)) @@ -8149,7 +8061,7 @@ intel_modeset_stage_output_state(struct drm_device *dev, struct intel_encoder *encoder; int count, ro; - /* The upper layers ensure that we either disabl a crtc or have a list + /* The upper layers ensure that we either disable a crtc or have a list * of connectors. For paranoia, double-check this. */ WARN_ON(!set->fb && (set->num_connectors != 0)); WARN_ON(set->fb && (set->num_connectors == 0)); @@ -8251,14 +8163,9 @@ static int intel_crtc_set_config(struct drm_mode_set *set) BUG_ON(!set->crtc); BUG_ON(!set->crtc->helper_private); - if (!set->mode) - set->fb = NULL; - - /* The fb helper likes to play gross jokes with ->mode_set_config. - * Unfortunately the crtc helper doesn't do much at all for this case, - * so we have to cope with this madness until the fb helper is fixed up. */ - if (set->fb && set->num_connectors == 0) - return 0; + /* Enforce sane interface api - has been abused by the fb helper. */ + BUG_ON(!set->mode && set->fb); + BUG_ON(set->fb && set->num_connectors == 0); if (set->fb) { DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", @@ -8302,11 +8209,11 @@ static int intel_crtc_set_config(struct drm_mode_set *set) drm_mode_debug_printmodeline(set->mode); } - if (!intel_set_mode(set->crtc, set->mode, - set->x, set->y, set->fb)) { - DRM_ERROR("failed to set mode on [CRTC:%d]\n", - set->crtc->base.id); - ret = -EINVAL; + ret = intel_set_mode(set->crtc, set->mode, + set->x, set->y, set->fb); + if (ret) { + DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n", + set->crtc->base.id, ret); goto fail; } } else if (config->fb_changed) { @@ -8323,8 +8230,8 @@ fail: /* Try to restore the config */ if (config->mode_changed && - !intel_set_mode(save_set.crtc, save_set.mode, - save_set.x, save_set.y, save_set.fb)) + intel_set_mode(save_set.crtc, save_set.mode, + save_set.x, save_set.y, save_set.fb)) DRM_ERROR("failed to restore config after modeset failure\n"); out_config: @@ -8343,7 +8250,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = { static void intel_cpu_pll_init(struct drm_device *dev) { - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_ddi_pll_init(dev); } @@ -8373,6 +8280,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc = kmalloc(sizeof(struct intel_crtc) + (INTELFB_CONN_LIMIT * sizeof(struct drm_connector *)), M_DRM, M_WAITOK | M_ZERO); + if (intel_crtc == NULL) + return; drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs); @@ -8479,11 +8388,10 @@ static void intel_setup_outputs(struct drm_device *dev) I915_WRITE(PFIT_CONTROL, 0); } - if (!(IS_HASWELL(dev) && - (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES))) + if (!IS_ULT(dev)) intel_crt_init(dev); - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { int found; /* Haswell uses DDI functions to detect digital outputs */ @@ -8530,23 +8438,18 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_D) & DP_DETECTED) intel_dp_init(dev, PCH_DP_D, PORT_D); } else if (IS_VALLEYVIEW(dev)) { - int found; - /* Check for built-in panel first. Shares lanes with HDMI on SDVOC */ - if (I915_READ(DP_C) & DP_DETECTED) - intel_dp_init(dev, DP_C, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_C, PORT_C); - if (I915_READ(SDVOB) & PORT_DETECTED) { - /* SDVOB multiplex with HDMIB */ - found = intel_sdvo_init(dev, SDVOB, true); - if (!found) - intel_hdmi_init(dev, SDVOB, PORT_B); - if (!found && (I915_READ(DP_B) & DP_DETECTED)) - intel_dp_init(dev, DP_B, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + SDVOB) & PORT_DETECTED) { + intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOB, PORT_B); + if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED) + intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B); } - if (I915_READ(SDVOC) & PORT_DETECTED) - intel_hdmi_init(dev, SDVOC, PORT_C); + if (I915_READ(VLV_DISPLAY_BASE + SDVOC) & PORT_DETECTED) + intel_hdmi_init(dev, VLV_DISPLAY_BASE + SDVOC, PORT_C); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { bool found = false; @@ -8709,14 +8612,15 @@ int intel_framebuffer_init(struct drm_device *dev, if (mode_cmd->offsets[0] != 0) return -EINVAL; + drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); + intel_fb->obj = obj; + ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); if (ret) { DRM_ERROR("framebuffer init failed %d\n", ret); return ret; } - drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); - intel_fb->obj = obj; return 0; } @@ -8746,7 +8650,7 @@ static void intel_init_display(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; /* We always want a DPMS function */ - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; @@ -8808,8 +8712,9 @@ static void intel_init_display(struct drm_device *dev) } else if (IS_HASWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; dev_priv->display.write_eld = haswell_write_eld; - } else - dev_priv->display.update_wm = NULL; + dev_priv->display.modeset_global_resources = + haswell_modeset_global_resources; + } } else if (IS_G4X(dev)) { dev_priv->display.write_eld = g4x_write_eld; } @@ -8932,9 +8837,6 @@ static struct intel_quirk intel_quirks[] = { /* Acer Aspire 5734Z must invert backlight brightness */ { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, - /* Acer Aspire 4736Z */ - { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, - /* Acer/eMachines G725 */ { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, @@ -8943,6 +8845,9 @@ static struct intel_quirk intel_quirks[] = { /* Acer/Packard Bell NCL20 */ { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, + + /* Acer Aspire 4736Z */ + { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, }; static void intel_init_quirks(struct drm_device *dev) @@ -8971,12 +8876,7 @@ static void i915_disable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u8 sr1; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; + u32 vga_reg = i915_vgacntrl_reg(dev); #if 0 vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); @@ -8995,18 +8895,15 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { - /* We attempt to init the necessary power wells early in the initialization - * time, so the subsystems that expect power to be enabled can work. - */ - intel_init_power_wells(dev); + intel_init_power_well(dev); intel_prepare_ddi(dev); intel_init_clock_gating(dev); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_enable_gt_powersave(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); } void intel_modeset_init(struct drm_device *dev) @@ -9058,6 +8955,9 @@ void intel_modeset_init(struct drm_device *dev) /* Just disable it once at startup */ i915_disable_vga(dev); intel_setup_outputs(dev); + + /* Just in case the BIOS is doing something questionable. */ + intel_disable_fbc(dev); } static void @@ -9239,20 +9139,14 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) * the crtc fixup. */ } -static void i915_redisable_vga(struct drm_device *dev) +void i915_redisable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 vga_reg; - - if (HAS_PCH_SPLIT(dev)) - vga_reg = CPU_VGACNTRL; - else - vga_reg = VGACNTRL; + u32 vga_reg = i915_vgacntrl_reg(dev); if (I915_READ(vga_reg) != VGA_DISP_DISABLE) { DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); - I915_WRITE(vga_reg, VGA_DISP_DISABLE); - POSTING_READ(vga_reg); + i915_disable_vga(dev); } } @@ -9268,7 +9162,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, struct intel_encoder *encoder; struct intel_connector *connector; - if (IS_HASWELL(dev)) { + if (HAS_DDI(dev)) { tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); if (tmp & TRANS_DDI_FUNC_ENABLE) { @@ -9309,7 +9203,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, crtc->active ? "enabled" : "disabled"); } - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_ddi_setup_hw_pll_state(dev); list_for_each_entry(encoder, &dev->mode_config.encoder_list, @@ -9359,10 +9253,16 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, } if (force_restore) { + /* + * We need to use raw interfaces for restoring state to avoid + * checking (bogus) intermediate states. + */ for_each_pipe(pipe) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - intel_set_mode(&crtc->base, &crtc->base.mode, - crtc->base.x, crtc->base.y, crtc->base.fb); + struct drm_crtc *crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + + __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, + crtc->fb); } i915_redisable_vga(dev); @@ -9381,9 +9281,7 @@ void intel_modeset_gem_init(struct drm_device *dev) intel_setup_overlay(dev); - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); intel_modeset_setup_hw_state(dev, false); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); } void intel_modeset_cleanup(struct drm_device *dev) @@ -9393,7 +9291,7 @@ void intel_modeset_cleanup(struct drm_device *dev) struct intel_crtc *intel_crtc; drm_kms_helper_poll_fini(dev); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); #if 0 intel_unregister_dsm_handler(); @@ -9417,7 +9315,7 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_VALLEYVIEW(dev)) vlv_init_dpio(dev); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); /* Disable the irq before mode object teardown, for the irq might * enqueue unpin/hotplug work. */ @@ -9432,6 +9330,8 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_panel_destroy_backlight(dev); drm_mode_config_cleanup(dev); + + intel_cleanup_overlay(dev); } /* @@ -9544,38 +9444,40 @@ intel_display_capture_error_state(struct drm_device *dev) } void -intel_display_print_error_state(struct sbuf *m, +intel_display_print_error_state(struct seq_file *m, struct drm_device *dev, struct intel_display_error_state *error) { + drm_i915_private_t *dev_priv = dev->dev_private; int i; - for (i = 0; i < 2; i++) { - sbuf_printf(m, "Pipe [%d]:\n", i); - sbuf_printf(m, " CONF: %08x\n", error->pipe[i].conf); - sbuf_printf(m, " SRC: %08x\n", error->pipe[i].source); - sbuf_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); - sbuf_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); - sbuf_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); - sbuf_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); - sbuf_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); - sbuf_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); - - sbuf_printf(m, "Plane [%d]:\n", i); - sbuf_printf(m, " CNTR: %08x\n", error->plane[i].control); - sbuf_printf(m, " STRIDE: %08x\n", error->plane[i].stride); - sbuf_printf(m, " SIZE: %08x\n", error->plane[i].size); - sbuf_printf(m, " POS: %08x\n", error->plane[i].pos); - sbuf_printf(m, " ADDR: %08x\n", error->plane[i].addr); + seq_printf(m, "Num Pipes: %d\n", dev_priv->num_pipe); + for_each_pipe(i) { + seq_printf(m, "Pipe [%d]:\n", i); + seq_printf(m, " CONF: %08x\n", error->pipe[i].conf); + seq_printf(m, " SRC: %08x\n", error->pipe[i].source); + seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); + seq_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); + seq_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); + seq_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); + seq_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); + seq_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); + + seq_printf(m, "Plane [%d]:\n", i); + seq_printf(m, " CNTR: %08x\n", error->plane[i].control); + seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride); + seq_printf(m, " SIZE: %08x\n", error->plane[i].size); + seq_printf(m, " POS: %08x\n", error->plane[i].pos); + seq_printf(m, " ADDR: %08x\n", error->plane[i].addr); if (INTEL_INFO(dev)->gen >= 4) { - sbuf_printf(m, " SURF: %08x\n", error->plane[i].surface); - sbuf_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); + seq_printf(m, " SURF: %08x\n", error->plane[i].surface); + seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset); } - sbuf_printf(m, "Cursor [%d]:\n", i); - sbuf_printf(m, " CNTR: %08x\n", error->cursor[i].control); - sbuf_printf(m, " POS: %08x\n", error->cursor[i].position); - sbuf_printf(m, " BASE: %08x\n", error->cursor[i].base); + seq_printf(m, "Cursor [%d]:\n", i); + seq_printf(m, " CNTR: %08x\n", error->cursor[i].control); + seq_printf(m, " POS: %08x\n", error->cursor[i].position); + seq_printf(m, " BASE: %08x\n", error->cursor[i].base); } } #endif diff --git a/sys/dev/drm/i915/intel_dp.c b/sys/dev/drm/i915/intel_dp.c index 608ce1beba..caa4e95145 100644 --- a/sys/dev/drm/i915/intel_dp.c +++ b/sys/dev/drm/i915/intel_dp.c @@ -147,15 +147,6 @@ intel_dp_max_link_bw(struct intel_dp *intel_dp) return max_link_bw; } -static int -intel_dp_link_clock(uint8_t link_bw) -{ - if (link_bw == DP_LINK_BW_2_7) - return 270000; - else - return 162000; -} - /* * The units on the numbers in the next two are... bizarre. Examples will * make it clearer; this one parallels an example in the eDP spec. @@ -190,7 +181,8 @@ intel_dp_adjust_dithering(struct intel_dp *intel_dp, struct drm_display_mode *mode, bool adjust_mode) { - int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); + int max_link_clock = + drm_dp_bw_code_to_link_rate(intel_dp_max_link_bw(intel_dp)); int max_lanes = drm_dp_max_lane_count(intel_dp->dpcd); int max_rate, mode_rate; @@ -329,6 +321,49 @@ intel_dp_check_edp(struct intel_dp *intel_dp) } } +static uint32_t +intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t ch_ctl = intel_dp->output_reg + 0x10; + uint32_t status; + bool done; + + if (IS_HASWELL(dev)) { + switch (intel_dig_port->port) { + case PORT_A: + ch_ctl = DPA_AUX_CH_CTL; + break; + case PORT_B: + ch_ctl = PCH_DPB_AUX_CH_CTL; + break; + case PORT_C: + ch_ctl = PCH_DPC_AUX_CH_CTL; + break; + case PORT_D: + ch_ctl = PCH_DPD_AUX_CH_CTL; + break; + default: + BUG(); + } + } + +#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0) + if (has_aux_irq) + done = wait_event_timeout(dev_priv->gmbus_wait_queue, C, + msecs_to_jiffies(10)); + else + done = wait_for_atomic(C, 10) == 0; + if (!done) + DRM_ERROR("dp aux hw did not signal timeout (has irq: %i)!\n", + has_aux_irq); +#undef C + + return status; +} + static int intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, @@ -340,11 +375,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dev->dev_private; uint32_t ch_ctl = output_reg + 0x10; uint32_t ch_data = ch_ctl + 4; - int i; - int recv_bytes; + int i, ret, recv_bytes; uint32_t status; uint32_t aux_clock_divider; int try, precharge; + bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev); + + /* dp aux is extremely sensitive to irq latency, hence request the + * lowest possible wakeup latency and so prevent the cpu from going into + * deep sleep states. + */ + pm_qos_update_request(&dev_priv->pm_qos, 0); if (IS_HASWELL(dev)) { switch (intel_dig_port->port) { @@ -378,7 +419,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * clock divider. */ if (is_cpu_edp(intel_dp)) { - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1; else if (IS_VALLEYVIEW(dev)) aux_clock_divider = 100; @@ -398,7 +439,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, /* Try to wait for any previous AUX channel activity */ for (try = 0; try < 3; try++) { - status = I915_READ(ch_ctl); + status = I915_READ_NOTRACE(ch_ctl); if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) break; msleep(1); @@ -407,7 +448,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, if (try == 3) { WARN(1, "dp_aux_ch not started status 0x%08x\n", I915_READ(ch_ctl)); - return -EBUSY; + ret = -EBUSY; + goto out; } /* Must try at least 3 times according to DP spec */ @@ -420,6 +462,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, /* Send the command and wait for it to complete */ I915_WRITE(ch_ctl, DP_AUX_CH_CTL_SEND_BUSY | + (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) | DP_AUX_CH_CTL_TIME_OUT_400us | (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) | (precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) | @@ -427,12 +470,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, DP_AUX_CH_CTL_DONE | DP_AUX_CH_CTL_TIME_OUT_ERROR | DP_AUX_CH_CTL_RECEIVE_ERROR); - for (;;) { - status = I915_READ(ch_ctl); - if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) - break; - udelay(100); - } + + status = intel_dp_aux_wait_done(intel_dp, has_aux_irq); /* Clear done status and any errors */ I915_WRITE(ch_ctl, @@ -450,7 +489,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, if ((status & DP_AUX_CH_CTL_DONE) == 0) { DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status); - return -EBUSY; + ret = -EBUSY; + goto out; } /* Check for timeout or receive error. @@ -458,14 +498,16 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, */ if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status); - return -EIO; + ret = -EIO; + goto out; } /* Timeouts occur when the device isn't connected, so they're * "normal" -- don't fill the kernel log with these */ if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { DRM_DEBUG_KMS("dp_aux_ch timeout status 0x%08x\n", status); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } /* Unload any bytes sent back from the other side */ @@ -478,7 +520,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, unpack_aux(I915_READ(ch_data + i), recv + i, recv_bytes - i); - return recv_bytes; + ret = recv_bytes; +out: + pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE); + + return ret; } /* Write data to the aux channel in native mode */ @@ -563,13 +609,12 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp, } static int -intel_dp_i2c_aux_ch(device_t idev, int mode, +intel_dp_i2c_aux_ch(struct device *adapter, int mode, uint8_t write_byte, uint8_t *read_byte) { - struct iic_dp_aux_data *data; - struct intel_dp *intel_dp; - uint16_t address; - + struct iic_dp_aux_data *data = device_get_softc(adapter); + struct intel_dp *intel_dp = data->priv; + uint16_t address = data->address; uint8_t msg[5]; uint8_t reply[2]; unsigned retry; @@ -577,10 +622,6 @@ intel_dp_i2c_aux_ch(device_t idev, int mode, int reply_bytes; int ret; - data = device_get_softc(idev); - intel_dp = data->priv; - address = data->address; - intel_dp_check_edp(intel_dp); /* Set up the command byte */ if (mode & MODE_I2C_READ) @@ -711,16 +752,35 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, return false; bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24; + + if (intel_dp->color_range_auto) { + /* + * See: + * CEA-861-E - 5.1 Default Encoding Parameters + * VESA DisplayPort Ver.1.2a - 5.1.1.1 Video Colorimetry + */ + if (bpp != 18 && drm_match_cea_mode(adjusted_mode) > 1) + intel_dp->color_range = DP_COLOR_RANGE_16_235; + else + intel_dp->color_range = 0; + } + + if (intel_dp->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); for (clock = 0; clock <= max_clock; clock++) { for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { - int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); + int link_bw_clock = + drm_dp_bw_code_to_link_rate(bws[clock]); + int link_avail = intel_dp_max_data_rate(link_bw_clock, + lane_count); if (mode_rate <= link_avail) { intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; - adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); + adjusted_mode->clock = link_bw_clock; DRM_DEBUG_KMS("DP link bw %02x lane " "count %d clock %d bpp %d\n", intel_dp->link_bw, intel_dp->lane_count, @@ -735,39 +795,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, return false; } -struct intel_dp_m_n { - uint32_t tu; - uint32_t gmch_m; - uint32_t gmch_n; - uint32_t link_m; - uint32_t link_n; -}; - -static void -intel_reduce_ratio(uint32_t *num, uint32_t *den) -{ - while (*num > 0xffffff || *den > 0xffffff) { - *num >>= 1; - *den >>= 1; - } -} - -static void -intel_dp_compute_m_n(int bpp, - int nlanes, - int pixel_clock, - int link_clock, - struct intel_dp_m_n *m_n) -{ - m_n->tu = 64; - m_n->gmch_m = (pixel_clock * bpp) >> 3; - m_n->gmch_n = link_clock * nlanes; - intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); - m_n->link_m = pixel_clock; - m_n->link_n = link_clock; - intel_reduce_ratio(&m_n->link_m, &m_n->link_n); -} - void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -778,7 +805,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int lane_count = 4; - struct intel_dp_m_n m_n; + struct intel_link_m_n m_n; int pipe = intel_crtc->pipe; enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder; int target_clock; @@ -811,8 +838,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, * the number of bytes_per_pixel post-LUT, which we always * set up for 8-bits of R/G/B, or 3 bytes total. */ - intel_dp_compute_m_n(intel_crtc->bpp, lane_count, - target_clock, adjusted_mode->clock, &m_n); + intel_link_compute_m_n(intel_crtc->bpp, lane_count, + target_clock, adjusted_mode->clock, &m_n); if (IS_HASWELL(dev)) { I915_WRITE(PIPE_DATA_M1(cpu_transcoder), @@ -854,6 +881,32 @@ void intel_dp_init_link_config(struct intel_dp *intel_dp) } } +static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpa_ctl; + + DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock); + dpa_ctl = I915_READ(DP_A); + dpa_ctl &= ~DP_PLL_FREQ_MASK; + + if (clock < 200000) { + /* For a long time we've carried around a ILK-DevA w/a for the + * 160MHz clock. If we're really unlucky, it's still required. + */ + DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n"); + dpa_ctl |= DP_PLL_FREQ_160MHZ; + } else { + dpa_ctl |= DP_PLL_FREQ_270MHZ; + } + + I915_WRITE(DP_A, dpa_ctl); + + POSTING_READ(DP_A); + udelay(500); +} + static void intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -929,7 +982,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, else intel_dp->DP |= DP_PLL_FREQ_270MHZ; } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { - intel_dp->DP |= intel_dp->color_range; + if (!HAS_PCH_SPLIT(dev)) + intel_dp->DP |= intel_dp->color_range; if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) intel_dp->DP |= DP_SYNC_HS_HIGH; @@ -953,6 +1007,9 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } else { intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } + + if (is_cpu_edp(intel_dp)) + ironlake_set_pll_edp(crtc, adjusted_mode->clock); } #define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) @@ -1060,6 +1117,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { pp = ironlake_get_pp_control(dev_priv); pp &= ~EDP_FORCE_VDD; @@ -1080,9 +1139,9 @@ static void ironlake_panel_vdd_work(struct work_struct *__work) struct intel_dp, panel_vdd_work); struct drm_device *dev = intel_dp_to_dev(intel_dp); - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); + mutex_lock(&dev->mode_config.mutex); ironlake_panel_vdd_off_sync(intel_dp); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + mutex_unlock(&dev->mode_config.mutex); } void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) @@ -1546,7 +1605,7 @@ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ST } static uint32_t -intel_dp_signal_levels(uint8_t train_set) +intel_gen4_signal_levels(uint8_t train_set) { uint32_t signal_levels = 0; @@ -1644,7 +1703,7 @@ intel_gen7_edp_signal_levels(uint8_t train_set) /* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */ static uint32_t -intel_dp_signal_levels_hsw(uint8_t train_set) +intel_hsw_signal_levels(uint8_t train_set) { int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | DP_TRAIN_PRE_EMPHASIS_MASK); @@ -1676,6 +1735,34 @@ intel_dp_signal_levels_hsw(uint8_t train_set) } } +/* Properly updates "DP" with the correct signal levels. */ +static void +intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + uint32_t signal_levels, mask; + uint8_t train_set = intel_dp->train_set[0]; + + if (IS_HASWELL(dev)) { + signal_levels = intel_hsw_signal_levels(train_set); + mask = DDI_BUF_EMP_MASK; + } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { + signal_levels = intel_gen7_edp_signal_levels(train_set); + mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; + } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { + signal_levels = intel_gen6_edp_signal_levels(train_set); + mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB; + } else { + signal_levels = intel_gen4_signal_levels(train_set); + mask = DP_VOLTAGE_MASK | DP_PRE_EMPHASIS_MASK; + } + + DRM_DEBUG_KMS("Using signal levels %08x\n", signal_levels); + + *DP = (*DP & ~mask) | signal_levels; +} + static bool intel_dp_set_link_train(struct intel_dp *intel_dp, uint32_t dp_reg_value, @@ -1699,14 +1786,18 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { case DP_TRAINING_PATTERN_DISABLE: - temp |= DP_TP_CTL_LINK_TRAIN_IDLE; - I915_WRITE(DP_TP_CTL(port), temp); - if (wait_for((I915_READ(DP_TP_STATUS(port)) & - DP_TP_STATUS_IDLE_DONE), 1)) - DRM_ERROR("Timed out waiting for DP idle patterns\n"); + if (port != PORT_A) { + temp |= DP_TP_CTL_LINK_TRAIN_IDLE; + I915_WRITE(DP_TP_CTL(port), temp); + + if (wait_for((I915_READ(DP_TP_STATUS(port)) & + DP_TP_STATUS_IDLE_DONE), 1)) + DRM_ERROR("Timed out waiting for DP idle patterns\n"); + + temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; + } - temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; temp |= DP_TP_CTL_LINK_TRAIN_NORMAL; break; @@ -1794,7 +1885,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) int voltage_tries, loop_tries; uint32_t DP = intel_dp->DP; - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_ddi_prepare_link_retrain(encoder); /* Write the link configuration data */ @@ -1812,24 +1903,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint8_t link_status[DP_LINK_STATUS_SIZE]; - uint32_t signal_levels; - - if (IS_HASWELL(dev)) { - signal_levels = intel_dp_signal_levels_hsw( - intel_dp->train_set[0]); - DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels; - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { - signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; - } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { - signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; - } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; - } - DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n", - signal_levels); + + intel_dp_set_signal_levels(intel_dp, &DP); /* Set training pattern 1 */ if (!intel_dp_set_link_train(intel_dp, DP, @@ -1885,7 +1960,6 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) void intel_dp_complete_link_train(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp_to_dev(intel_dp); bool channel_eq = false; int tries, cr_tries; uint32_t DP = intel_dp->DP; @@ -1895,8 +1969,6 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) cr_tries = 0; channel_eq = false; for (;;) { - /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ - uint32_t signal_levels; uint8_t link_status[DP_LINK_STATUS_SIZE]; if (cr_tries > 5) { @@ -1905,19 +1977,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; } - if (IS_HASWELL(dev)) { - signal_levels = intel_dp_signal_levels_hsw(intel_dp->train_set[0]); - DP = (DP & ~DDI_BUF_EMP_MASK) | signal_levels; - } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) { - signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; - } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { - signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; - } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); - DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; - } + intel_dp_set_signal_levels(intel_dp, &DP); /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, DP, @@ -1967,6 +2027,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = + to_intel_crtc(intel_dig_port->base.base.crtc); uint32_t DP = intel_dp->DP; /* @@ -1984,7 +2046,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) * intel_ddi_prepare_link_retrain will take care of redoing the link * train. */ - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) return; if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)) @@ -2001,7 +2063,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) } POSTING_READ(intel_dp->output_reg); - msleep(17); + /* We don't really know why we're doing this */ + intel_wait_for_vblank(dev, intel_crtc->pipe); if (HAS_PCH_IBX(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { @@ -2021,19 +2084,14 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - if (crtc == NULL) { - /* We can arrive here never having been attached - * to a CRTC, for instance, due to inheriting - * random state from the BIOS. - * - * If the pipe is not running, play safe and - * wait for the clocks to stabilise before - * continuing. - */ + if (WARN_ON(crtc == NULL)) { + /* We should never try to disable a port without a crtc + * attached. For paranoia keep the code around for a + * bit. */ POSTING_READ(intel_dp->output_reg); msleep(50); } else - intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); + intel_wait_for_vblank(dev, intel_crtc->pipe); } DP &= ~DP_AUDIO_OUTPUT_ENABLE; @@ -2045,10 +2103,20 @@ intel_dp_link_down(struct intel_dp *intel_dp) static bool intel_dp_get_dpcd(struct intel_dp *intel_dp) { + char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3]; + if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, sizeof(intel_dp->dpcd)) == 0) return false; /* aux transfer failed */ + ksnprintf(dpcd_hex_dump, + sizeof(dpcd_hex_dump), + "%02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n", + intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], + intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5], + intel_dp->dpcd[6], intel_dp->dpcd[7]); + DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); + if (intel_dp->dpcd[DP_DPCD_REV] == 0) return false; /* DPCD not present */ @@ -2209,6 +2277,8 @@ static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum drm_connector_status status; /* Can't disconnect eDP, but you can close the lid... */ @@ -2219,6 +2289,9 @@ ironlake_dp_detect(struct intel_dp *intel_dp) return status; } + if (!ibx_digital_port_connected(dev_priv, intel_dig_port)) + return connector_status_disconnected; + return intel_dp_detect_dpcd(intel_dp); } @@ -2227,17 +2300,18 @@ g4x_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); uint32_t bit; - switch (intel_dp->output_reg) { - case DP_B: - bit = DPB_HOTPLUG_LIVE_STATUS; + switch (intel_dig_port->port) { + case PORT_B: + bit = PORTB_HOTPLUG_LIVE_STATUS; break; - case DP_C: - bit = DPC_HOTPLUG_LIVE_STATUS; + case PORT_C: + bit = PORTC_HOTPLUG_LIVE_STATUS; break; - case DP_D: - bit = DPD_HOTPLUG_LIVE_STATUS; + case PORT_D: + bit = PORTD_HOTPLUG_LIVE_STATUS; break; default: return connector_status_unknown; @@ -2293,13 +2367,6 @@ intel_dp_get_edid_modes(struct drm_connector *connector, struct device *adapter) return intel_ddc_get_modes(connector, adapter); } - -/** - * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. - * - * \return true if DP port is connected. - * \return false if DP port is disconnected. - */ static enum drm_connector_status intel_dp_detect(struct drm_connector *connector, bool force) { @@ -2309,7 +2376,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct drm_device *dev = connector->dev; enum drm_connector_status status; struct edid *edid = NULL; - char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3]; intel_dp->has_audio = false; @@ -2318,14 +2384,6 @@ intel_dp_detect(struct drm_connector *connector, bool force) else status = g4x_dp_detect(intel_dp); - ksnprintf(dpcd_hex_dump, - sizeof(dpcd_hex_dump), - "%02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n", - intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], - intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5], - intel_dp->dpcd[6], intel_dp->dpcd[7]); - DRM_DEBUG_KMS("DPCD: %s\n", dpcd_hex_dump); - if (status != connector_status_connected) return status; @@ -2426,10 +2484,21 @@ intel_dp_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_dp->color_range) - return 0; - - intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_dp->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_dp->color_range_auto = false; + intel_dp->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_dp->color_range_auto = false; + intel_dp->color_range = DP_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } @@ -2452,11 +2521,8 @@ intel_dp_set_property(struct drm_connector *connector, return -EINVAL; done: - if (intel_encoder->base.crtc) { - struct drm_crtc *crtc = intel_encoder->base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_encoder->base.crtc) + intel_crtc_restore_mode(intel_encoder->base.crtc); return 0; } @@ -2484,7 +2550,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) { struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_dp *intel_dp = &intel_dig_port->dp; - struct drm_device *dev = encoder->dev; + struct drm_device *dev = intel_dp_to_dev(intel_dp); if (intel_dp->dp_iic_bus != NULL) { if (intel_dp->adapter != NULL) { @@ -2496,7 +2562,9 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) drm_encoder_cleanup(encoder); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + mutex_lock(&dev->mode_config.mutex); ironlake_panel_vdd_off_sync(intel_dp); + mutex_unlock(&dev->mode_config.mutex); } kfree(intel_dig_port, M_DRM); } @@ -2579,6 +2647,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_dp->color_range_auto = true; if (is_edp(intel_dp)) { drm_mode_create_scaling_mode_property(connector->dev); @@ -2770,7 +2839,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, drm_sysfs_connector_add(connector); #endif - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; else intel_connector->get_hw_state = intel_connector_get_hw_state; @@ -2782,15 +2851,15 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, name = "DPDDC-A"; break; case PORT_B: - dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; name = "DPDDC-B"; break; case PORT_C: - dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; name = "DPDDC-C"; break; case PORT_D: - dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; name = "DPDDC-D"; break; default: diff --git a/sys/dev/drm/i915/intel_drv.h b/sys/dev/drm/i915/intel_drv.h index d5f62efb33..f0e6a8fb68 100644 --- a/sys/dev/drm/i915/intel_drv.h +++ b/sys/dev/drm/i915/intel_drv.h @@ -21,13 +21,11 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. - * */ +#ifndef __INTEL_DRV_H__ +#define __INTEL_DRV_H__ -#ifndef DRM_INTEL_DRV_H -#define DRM_INTEL_DRV_H - -#include +#include #include #include "i915_drv.h" #include @@ -65,30 +63,16 @@ ret__; \ }) -#define _intel_wait_for(DEV, COND, MS, W, WMSG) \ -({ \ - int end, ret; \ - \ - end = ticks + (MS) * hz / 1000; \ - ret = 0; \ - \ - while (!(COND)) { \ - if (time_after(ticks, end)) { \ - ret = -ETIMEDOUT; \ - break; \ - } \ - DELAY(1000); \ - } \ - \ - ret; \ -}) - #define wait_for(COND, MS) _wait_for(COND, MS, 1) #define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0) #define KHz(x) (1000*x) #define MHz(x) KHz(1000*x) +/* + * Display related stuff + */ + /* store information about an Ixxx DVO */ /* The i830->i865 use multiple DVOs with multiple i2cs */ /* the i915, i945 have a single sDVO i2c bus - which is different */ @@ -125,6 +109,11 @@ * timings in the mode to prevent the crtc fixup from overwriting them. * Currently only lvds needs that. */ #define INTEL_MODE_CRTC_TIMINGS_SET (0x20) +/* + * Set when limited 16-235 (as opposed to full 0-255) RGB color range is + * to be used. + */ +#define INTEL_MODE_LIMITED_COLOR_RANGE (0x40) static inline void intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, @@ -169,8 +158,9 @@ struct intel_encoder { bool cloneable; bool connectors_active; void (*hot_plug)(struct intel_encoder *); - void (*enable)(struct intel_encoder *); + void (*pre_pll_enable)(struct intel_encoder *); void (*pre_enable)(struct intel_encoder *); + void (*enable)(struct intel_encoder *); void (*disable)(struct intel_encoder *); void (*post_disable)(struct intel_encoder *); /* Read out the current hw state of this connector, returning true if @@ -221,6 +211,7 @@ struct intel_crtc { * some outputs connected to this crtc. */ bool active; + bool eld_vld; bool primary_disabled; /* is the crtc obscured by a plane? */ bool lowfreq_avail; struct intel_overlay *overlay; @@ -244,6 +235,9 @@ struct intel_crtc { /* We can share PLLs across outputs if the timings match */ struct intel_pch_pll *pch_pll; uint32_t ddi_pll_sel; + + /* reset counter value when the last flip was submitted */ + unsigned int reset_counter; }; struct intel_plane { @@ -299,6 +293,9 @@ struct cxsr_latency { #define DIP_LEN_AVI 13 #define DIP_AVI_PR_1 0 #define DIP_AVI_PR_2 1 +#define DIP_AVI_RGB_QUANT_RANGE_DEFAULT (0 << 2) +#define DIP_AVI_RGB_QUANT_RANGE_LIMITED (1 << 2) +#define DIP_AVI_RGB_QUANT_RANGE_FULL (2 << 2) #define DIP_TYPE_SPD 0x83 #define DIP_VERSION_SPD 0x1 @@ -332,7 +329,7 @@ struct dip_infoframe { uint8_t ITC_EC_Q_SC; /* PB4 - VIC 6:0 */ uint8_t VIC; - /* PB5 - PR 3:0 */ + /* PB5 - YQ 7:6, CN 5:4, PR 3:0 */ uint8_t YQ_CN_PR; /* PB6 to PB13 */ uint16_t top_bar_end; @@ -353,9 +350,11 @@ struct intel_hdmi { u32 sdvox_reg; int ddc_bus; uint32_t color_range; + bool color_range_auto; bool has_hdmi_sink; bool has_audio; enum hdmi_force_audio force_audio; + bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, struct dip_infoframe *frame); void (*set_infoframes)(struct drm_encoder *encoder, @@ -372,6 +371,7 @@ struct intel_dp { bool has_audio; enum hdmi_force_audio force_audio; uint32_t color_range; + bool color_range_auto; uint8_t link_bw; uint8_t lane_count; uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; @@ -379,7 +379,7 @@ struct intel_dp { device_t dp_iic_bus; device_t adapter; bool is_pch_edp; - uint8_t train_set[4]; + uint8_t train_set[4]; int panel_power_up_delay; int panel_power_down_delay; int panel_power_cycle_delay; @@ -415,7 +415,6 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane) struct intel_unpin_work { struct work_struct work; struct drm_crtc *crtc; - struct drm_device *dev; struct drm_i915_gem_object *old_fb_obj; struct drm_i915_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; @@ -460,6 +459,7 @@ extern void intel_mark_busy(struct drm_device *dev); extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj); extern void intel_mark_idle(struct drm_device *dev); extern bool intel_lvds_init(struct drm_device *dev); +extern bool intel_is_dual_link_lvds(struct drm_device *dev); extern void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, @@ -519,9 +519,10 @@ struct intel_set_config { bool mode_changed; }; -extern bool intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y, struct drm_framebuffer *old_fb); +extern int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y, struct drm_framebuffer *old_fb); extern void intel_modeset_disable(struct drm_device *dev); +extern void intel_crtc_restore_mode(struct drm_crtc *crtc); extern void intel_crtc_load_lut(struct drm_crtc *crtc); extern void intel_crtc_update_dpms(struct drm_crtc *crtc); extern void intel_encoder_noop(struct drm_encoder *encoder); @@ -532,6 +533,7 @@ extern void intel_connector_dpms(struct drm_connector *, int mode); extern bool intel_connector_get_hw_state(struct intel_connector *connector); extern void intel_modeset_check_state(struct drm_device *dev); + static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector) { return to_intel_connector(connector)->encoder; @@ -562,6 +564,9 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) return container_of(intel_hdmi, struct intel_digital_port, hdmi); } +bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, + struct intel_digital_port *port); + extern void intel_connector_attach_encoder(struct intel_connector *connector, struct intel_encoder *encoder); extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector); @@ -588,6 +593,7 @@ extern bool intel_get_load_detect_pipe(struct drm_connector *connector, extern void intel_release_load_detect_pipe(struct drm_connector *connector, struct intel_load_detect_pipe *old); +extern void intelfb_restore(void); extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno); extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, @@ -604,8 +610,9 @@ extern int intel_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_i915_gem_object *obj); extern int intel_fbdev_init(struct drm_device *dev); +extern void intel_fbdev_initial_config(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); - +extern void intel_fbdev_set_suspend(struct drm_device *dev, int state); extern void intel_prepare_page_flip(struct drm_device *dev, int plane); extern void intel_finish_page_flip(struct drm_device *dev, int pipe); extern void intel_finish_page_flip_plane(struct drm_device *dev, int plane); @@ -664,7 +671,8 @@ extern void intel_update_fbc(struct drm_device *dev); extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv); extern void intel_gpu_ips_teardown(void); -extern void intel_init_power_wells(struct drm_device *dev); +extern void intel_init_power_well(struct drm_device *dev); +extern void intel_set_power_well(struct drm_device *dev, bool enable); extern void intel_enable_gt_powersave(struct drm_device *dev); extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); diff --git a/sys/dev/drm/i915/intel_fb.c b/sys/dev/drm/i915/intel_fb.c index 28c92ef6c9..9391ab5bf4 100644 --- a/sys/dev/drm/i915/intel_fb.c +++ b/sys/dev/drm/i915/intel_fb.c @@ -22,10 +22,14 @@ * * Authors: * David Airlie - * - * $FreeBSD: head/sys/dev/drm2/i915/intel_fb.c 251961 2013-06-18 20:19:09Z kib $ */ +#include +#include +#include +#include +#include + #include #include #include @@ -33,16 +37,33 @@ #include #include "i915_drv.h" -static int intelfb_create(struct intel_fbdev *ifbdev, +#if 0 +static struct fb_ops intelfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, + .fb_debug_enter = drm_fb_helper_debug_enter, + .fb_debug_leave = drm_fb_helper_debug_leave, +}; +#endif + +static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { + struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; struct drm_device *dev = ifbdev->helper.dev; #if 0 struct drm_i915_private *dev_priv = dev->dev_private; struct fb_info *info; #endif struct drm_framebuffer *fb; - struct drm_mode_fb_cmd2 mode_cmd; + struct drm_mode_fb_cmd2 mode_cmd = {}; struct drm_i915_gem_object *obj; int size, ret; @@ -53,24 +74,26 @@ static int intelfb_create(struct intel_fbdev *ifbdev, mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = roundup2(mode_cmd.width * ((sizes->surface_bpp + 7) / - 8), 64); + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) / + 8), 64); mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); size = mode_cmd.pitches[0] * mode_cmd.height; - size = roundup2(size, PAGE_SIZE); + size = ALIGN(size, PAGE_SIZE); obj = i915_gem_alloc_object(dev, size); + if (obj == NULL) + obj = i915_gem_alloc_object(dev, size); if (!obj) { DRM_ERROR("failed to allocate framebuffer\n"); ret = -ENOMEM; goto out; } - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(dev, obj, false); + ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) { DRM_ERROR("failed to pin fb: %d\n", ret); goto out_unref; @@ -113,8 +136,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev, goto out_unpin; } info->apertures->ranges[0].base = dev->mode_config.fb_base; - info->apertures->ranges[0].size = - dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT; + info->apertures->ranges[0].size = dev_priv->gtt.mappable_end; info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset; info->fix.smem_len = size; @@ -131,6 +153,13 @@ static int intelfb_create(struct intel_fbdev *ifbdev, drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height); + /* If the object is shmemfs backed, it will have given us zeroed pages. + * If the object is stolen however, it will be full of whatever + * garbage was left in there. + */ + if (ifbdev->ifb.obj->stolen) + memset_io(info->screen_base, 0, info->screen_size); + /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ #endif @@ -138,10 +167,9 @@ static int intelfb_create(struct intel_fbdev *ifbdev, fb->width, fb->height, obj->gtt_offset, obj); - DRM_UNLOCK(dev); -#if 1 - KIB_NOTYET(); -#else + + mutex_unlock(&dev->struct_mutex); +#if 0 vga_switcheroo_client_fb_set(dev->pdev, info); #endif return 0; @@ -150,31 +178,15 @@ out_unpin: i915_gem_object_unpin(obj); out_unref: drm_gem_object_unreference(&obj->base); - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); out: return ret; } -static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; - int new_fb = 0; - int ret; - - if (!helper->fb) { - ret = intelfb_create(ifbdev, sizes); - if (ret) - return ret; - new_fb = 1; - } - return new_fb; -} - static struct drm_fb_helper_funcs intel_fb_helper_funcs = { .gamma_set = intel_crtc_fb_gamma_set, .gamma_get = intel_crtc_fb_gamma_get, - .fb_probe = intel_fb_find_or_create_single, + .fb_probe = intelfb_create, }; static void intel_fbdev_destroy(struct drm_device *dev, @@ -198,6 +210,7 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&ifbdev->helper); + drm_framebuffer_unregister_private(&ifb->base); drm_framebuffer_cleanup(&ifb->base); if (ifb->obj) { drm_gem_object_unreference_unlocked(&ifb->obj->base); @@ -213,8 +226,9 @@ int intel_fbdev_init(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; int ret; - ifbdev = kmalloc(sizeof(struct intel_fbdev), M_DRM, - M_WAITOK | M_ZERO); + ifbdev = kmalloc(sizeof(struct intel_fbdev), M_DRM, M_WAITOK | M_ZERO); + if (!ifbdev) + return -ENOMEM; dev_priv->fbdev = ifbdev; ifbdev->helper.funcs = &intel_fb_helper_funcs; @@ -223,16 +237,24 @@ int intel_fbdev_init(struct drm_device *dev) dev_priv->num_pipe, INTELFB_CONN_LIMIT); if (ret) { - drm_free(ifbdev, M_DRM); + kfree(ifbdev, M_DRM); return ret; } drm_fb_helper_single_add_all_connectors(&ifbdev->helper); - drm_fb_helper_initial_config(&ifbdev->helper, 32); sc_txtmouse_no_retrace_wait = 1; + return 0; } +void intel_fbdev_initial_config(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + /* Due to peculiar init order wrt to hpd handling this is separate. */ + drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32); +} + void intel_fbdev_fini(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -240,10 +262,33 @@ void intel_fbdev_fini(struct drm_device *dev) return; intel_fbdev_destroy(dev, dev_priv->fbdev); - drm_free(dev_priv->fbdev, M_DRM); + kfree(dev_priv->fbdev, M_DRM); dev_priv->fbdev = NULL; } +void intel_fbdev_set_suspend(struct drm_device *dev, int state) +{ +#if 0 + drm_i915_private_t *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev = dev_priv->fbdev; + struct fb_info *info; + + if (!ifbdev) + return; + + info = ifbdev->helper.fbdev; + + /* On resume from hibernation: If the object is shmemfs backed, it has + * been restored from swap. If the object is stolen however, it will be + * full of whatever garbage was left in there. + */ + if (!state && ifbdev->ifb.obj->stolen) + memset_io(info->screen_base, 0, info->screen_size); + + fb_set_suspend(info, state); +#endif +} + void intel_fb_output_poll_changed(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -257,7 +302,7 @@ void intel_fb_restore_mode(struct drm_device *dev) struct drm_mode_config *config = &dev->mode_config; struct drm_plane *plane; - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); + drm_modeset_lock_all(dev); ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); if (ret) @@ -265,7 +310,8 @@ void intel_fb_restore_mode(struct drm_device *dev) /* Be sure to shut off any planes that may be active */ list_for_each_entry(plane, &config->plane_list, head) - plane->funcs->disable_plane(plane); + if (plane->enabled) + plane->funcs->disable_plane(plane); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + drm_modeset_unlock_all(dev); } diff --git a/sys/dev/drm/i915/intel_hdmi.c b/sys/dev/drm/i915/intel_hdmi.c index 343d17cf9a..4ee3c8e807 100644 --- a/sys/dev/drm/i915/intel_hdmi.c +++ b/sys/dev/drm/i915/intel_hdmi.c @@ -26,6 +26,8 @@ * Jesse Barnes */ +#include +#include #include #include #include @@ -45,7 +47,7 @@ assert_hdmi_port_disabled(struct intel_hdmi *intel_hdmi) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t enabled_bits; - enabled_bits = IS_HASWELL(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; + enabled_bits = HAS_DDI(dev) ? DDI_BUF_CTL_ENABLE : SDVO_ENABLE; WARN(I915_READ(intel_hdmi->sdvox_reg) & enabled_bits, "HDMI port enabled, expecting disabled\n"); @@ -330,6 +332,7 @@ static void intel_set_infoframe(struct drm_encoder *encoder, static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, .ver = DIP_VERSION_AVI, @@ -339,7 +342,14 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2; - avi_if.body.avi.VIC = drm_mode_cea_vic(adjusted_mode); + if (intel_hdmi->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + + avi_if.body.avi.VIC = drm_match_cea_mode(adjusted_mode); intel_set_infoframe(encoder, &avi_if); } @@ -363,7 +373,8 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = VIDEO_DIP_CTL; u32 val = I915_READ(reg); u32 port; @@ -390,11 +401,11 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case SDVOB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case SDVOC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; default: @@ -427,7 +438,8 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); - struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); u32 port; @@ -446,14 +458,14 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, return; } - switch (intel_hdmi->sdvox_reg) { - case HDMIB: + switch (intel_dig_port->port) { + case PORT_B: port = VIDEO_DIP_PORT_B; break; - case HDMIC: + case PORT_C: port = VIDEO_DIP_PORT_C; break; - case HDMID: + case PORT_D: port = VIDEO_DIP_PORT_D; break; default: @@ -765,46 +777,38 @@ bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - return true; -} - -static bool g4x_hdmi_connected(struct intel_hdmi *intel_hdmi) -{ - struct drm_device *dev = intel_hdmi_to_dev(intel_hdmi); - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t bit; + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - switch (intel_hdmi->sdvox_reg) { - case SDVOB: - bit = HDMIB_HOTPLUG_LIVE_STATUS; - break; - case SDVOC: - bit = HDMIC_HOTPLUG_LIVE_STATUS; - break; - default: - bit = 0; - break; + if (intel_hdmi->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_hdmi->has_hdmi_sink && + drm_match_cea_mode(adjusted_mode) > 1) + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_hdmi->color_range = 0; } - return I915_READ(PORT_HOTPLUG_STAT) & bit; + if (intel_hdmi->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + + return true; } static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct intel_digital_port *intel_dig_port = hdmi_to_dig_port(intel_hdmi); struct intel_encoder *intel_encoder = &intel_dig_port->base; - struct drm_i915_private *dev_priv = connector->dev->dev_private; + struct drm_i915_private *dev_priv = dev->dev_private; struct edid *edid; enum drm_connector_status status = connector_status_disconnected; - if (IS_G4X(connector->dev) && !g4x_hdmi_connected(intel_hdmi)) - return status; - intel_hdmi->has_hdmi_sink = false; intel_hdmi->has_audio = false; + intel_hdmi->rgb_quant_range_selectable = false; edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); @@ -816,6 +820,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) intel_hdmi->has_hdmi_sink = drm_detect_hdmi_monitor(edid); intel_hdmi->has_audio = drm_detect_monitor_audio(edid); + intel_hdmi->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } drm_free(edid, M_DRM); } @@ -902,21 +908,29 @@ intel_hdmi_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_hdmi->color_range) - return 0; - - intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_hdmi->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_hdmi->color_range_auto = false; + intel_hdmi->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } return -EINVAL; done: - if (intel_dig_port->base.base.crtc) { - struct drm_crtc *crtc = intel_dig_port->base.base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_dig_port->base.base.crtc) + intel_crtc_restore_mode(intel_dig_port->base.base.crtc); return 0; } @@ -959,6 +973,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c { intel_attach_force_audio_property(connector); intel_attach_broadcast_rgb_property(connector); + intel_hdmi->color_range_auto = true; } void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, @@ -982,15 +997,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, switch (port) { case PORT_B: intel_hdmi->ddc_bus = GMBUS_PORT_DPB; - dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTB_HOTPLUG_INT_STATUS; break; case PORT_C: intel_hdmi->ddc_bus = GMBUS_PORT_DPC; - dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTC_HOTPLUG_INT_STATUS; break; case PORT_D: intel_hdmi->ddc_bus = GMBUS_PORT_DPD; - dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS; + dev_priv->hotplug_supported_mask |= PORTD_HOTPLUG_INT_STATUS; break; case PORT_A: /* Internal port only for eDP. */ @@ -1015,7 +1030,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_hdmi->set_infoframes = cpt_set_infoframes; } - if (IS_HASWELL(dev)) + if (HAS_DDI(dev)) intel_connector->get_hw_state = intel_ddi_connector_get_hw_state; else intel_connector->get_hw_state = intel_connector_get_hw_state; diff --git a/sys/dev/drm/i915/intel_i2c.c b/sys/dev/drm/i915/intel_i2c.c index 402cd2b8a8..94a5288b37 100644 --- a/sys/dev/drm/i915/intel_i2c.c +++ b/sys/dev/drm/i915/intel_i2c.c @@ -52,31 +52,50 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD: head/sys/dev/drm2/i915/intel_iic.c 249041 2013-04-03 08:27:35Z dumbbell $ */ #include +#include +#include #include +#include "intel_drv.h" #include #include "i915_drv.h" -#include "intel_drv.h" + #include #include #include #include "iicbus_if.h" #include "iicbb_if.h" -static int intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs); -static void intel_teardown_gmbus_m(struct drm_device *dev, int m); +struct gmbus_port { + const char *name; + int reg; +}; + +static const struct gmbus_port gmbus_ports[] = { + { "ssc", GPIOB }, + { "vga", GPIOA }, + { "panel", GPIOC }, + { "dpc", GPIOD }, + { "dpb", GPIOE }, + { "dpd", GPIOF }, +}; /* Intel GPIO access functions */ #define I2C_RISEFALL_TIME 10 -static void -intel_iic_quirk_set(struct drm_i915_private *dev_priv, bool enable) +void +intel_i2c_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0); + I915_WRITE(dev_priv->gpio_mmio_base + GMBUS4, 0); +} + +static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable) { u32 val; @@ -92,38 +111,54 @@ intel_iic_quirk_set(struct drm_i915_private *dev_priv, bool enable) I915_WRITE(DSPCLK_GATE_D, val); } -static u32 -intel_iic_get_reserved(device_t idev) +static u32 get_reserved(device_t idev) +{ + struct intel_iic_softc *sc = device_get_softc(idev); + struct drm_device *dev = sc->drm_dev; + struct drm_i915_private *dev_priv; + u32 reserved = 0; + + dev_priv = dev->dev_private; + + /* On most chips, these bits must be preserved in software. */ + if (!IS_I830(dev) && !IS_845G(dev)) + reserved = I915_READ_NOTRACE(sc->reg) & + (GPIO_DATA_PULLUP_DISABLE | + GPIO_CLOCK_PULLUP_DISABLE); + + return reserved; +} + +static int get_clock(device_t idev) { struct intel_iic_softc *sc; - struct drm_device *dev; struct drm_i915_private *dev_priv; u32 reserved; sc = device_get_softc(idev); - dev = sc->drm_dev; - dev_priv = dev->dev_private; + dev_priv = sc->drm_dev->dev_private; - if (!IS_I830(dev) && !IS_845G(dev)) { - reserved = I915_READ_NOTRACE(sc->reg) & - (GPIO_DATA_PULLUP_DISABLE | GPIO_CLOCK_PULLUP_DISABLE); - } else { - reserved = 0; - } + reserved = get_reserved(idev); - return (reserved); + I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_CLOCK_DIR_MASK); + I915_WRITE_NOTRACE(sc->reg, reserved); + return ((I915_READ_NOTRACE(sc->reg) & GPIO_CLOCK_VAL_IN) != 0); } -void -intel_i2c_reset(struct drm_device *dev) +static int get_data(device_t idev) { + struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; + u32 reserved; - dev_priv = dev->dev_private; - if (HAS_PCH_SPLIT(dev)) - I915_WRITE(PCH_GMBUS0, 0); - else - I915_WRITE(GMBUS0, 0); + sc = device_get_softc(idev); + dev_priv = sc->drm_dev->dev_private; + + reserved = get_reserved(idev); + + I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_DATA_DIR_MASK); + I915_WRITE_NOTRACE(sc->reg, reserved); + return ((I915_READ_NOTRACE(sc->reg) & GPIO_DATA_VAL_IN) != 0); } static int @@ -139,100 +174,328 @@ intel_iicbus_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr) return (0); } -static void -intel_iicbb_setsda(device_t idev, int val) +static void set_clock(device_t idev, int val) { struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - u32 reserved; - u32 data_bits; + u32 clock_bits, reserved; sc = device_get_softc(idev); dev_priv = sc->drm_dev->dev_private; - reserved = intel_iic_get_reserved(idev); + reserved = get_reserved(idev); if (val) - data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; + clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; else - data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | - GPIO_DATA_VAL_MASK; + clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | + GPIO_CLOCK_VAL_MASK; - I915_WRITE_NOTRACE(sc->reg, reserved | data_bits); + I915_WRITE_NOTRACE(sc->reg, reserved | clock_bits); POSTING_READ(sc->reg); } -static void -intel_iicbb_setscl(device_t idev, int val) +static void set_data(device_t idev, int val) { struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - u32 clock_bits, reserved; + u32 reserved; + u32 data_bits; sc = device_get_softc(idev); dev_priv = sc->drm_dev->dev_private; - reserved = intel_iic_get_reserved(idev); + reserved = get_reserved(idev); if (val) - clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; + data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; else - clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | - GPIO_CLOCK_VAL_MASK; + data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | + GPIO_DATA_VAL_MASK; - I915_WRITE_NOTRACE(sc->reg, reserved | clock_bits); + I915_WRITE_NOTRACE(sc->reg, reserved | data_bits); POSTING_READ(sc->reg); } +static const char *gpio_names[GMBUS_NUM_PORTS] = { + "ssc", + "vga", + "panel", + "dpc", + "dpb", + "dpd", +}; + static int -intel_iicbb_getsda(device_t idev) +intel_gpio_setup(device_t idev) { + static const int map_pin_to_reg[] = { + 0, + GPIOB, + GPIOA, + GPIOC, + GPIOD, + GPIOE, + GPIOF, + 0 + }; + struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - u32 reserved; + int pin; sc = device_get_softc(idev); + sc->drm_dev = device_get_softc(device_get_parent(idev)); dev_priv = sc->drm_dev->dev_private; + pin = device_get_unit(idev); - reserved = intel_iic_get_reserved(idev); + ksnprintf(sc->name, sizeof(sc->name), "i915 iicbb %s", gpio_names[pin]); + device_set_desc(idev, sc->name); - I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_DATA_DIR_MASK); - I915_WRITE_NOTRACE(sc->reg, reserved); - return ((I915_READ_NOTRACE(sc->reg) & GPIO_DATA_VAL_IN) != 0); + sc->reg0 = (pin + 1) | GMBUS_RATE_100KHZ; + sc->reg = map_pin_to_reg[pin + 1]; + if (HAS_PCH_SPLIT(dev_priv->dev)) + sc->reg += PCH_GPIOA - GPIOA; + + /* add generic bit-banging code */ + sc->iic_dev = device_add_child(idev, "iicbb", -1); + if (sc->iic_dev == NULL) + return (ENXIO); + device_quiet(sc->iic_dev); + bus_generic_attach(idev); + + return (0); } static int -intel_iicbb_getscl(device_t idev) +intel_i2c_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs) { + device_t bridge_dev; struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - u32 reserved; + int ret; + int i; - sc = device_get_softc(idev); + bridge_dev = device_get_parent(device_get_parent(idev)); + sc = device_get_softc(bridge_dev); dev_priv = sc->drm_dev->dev_private; - reserved = intel_iic_get_reserved(idev); + intel_i2c_reset(sc->drm_dev); + intel_i2c_quirk_set(dev_priv, true); + IICBB_SETSDA(bridge_dev, 1); + IICBB_SETSCL(bridge_dev, 1); + DELAY(I2C_RISEFALL_TIME); - I915_WRITE_NOTRACE(sc->reg, reserved | GPIO_CLOCK_DIR_MASK); - I915_WRITE_NOTRACE(sc->reg, reserved); - return ((I915_READ_NOTRACE(sc->reg) & GPIO_CLOCK_VAL_IN) != 0); + for (i = 0; i < nmsgs - 1; i++) { + /* force use of repeated start instead of default stop+start */ + msgs[i].flags |= IIC_M_NOSTOP; + } + ret = iicbus_transfer(idev, msgs, nmsgs); + IICBB_SETSDA(bridge_dev, 1); + IICBB_SETSCL(bridge_dev, 1); + intel_i2c_quirk_set(dev_priv, false); + + return (ret); +} + +/* + * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI + * mode. This results in spurious interrupt warnings if the legacy irq no. is + * shared with another device. The kernel then disables that interrupt source + * and so prevents the other device from working properly. + */ +#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) +static int +gmbus_wait_hw_status(struct drm_i915_private *dev_priv, + u32 gmbus2_status, + u32 gmbus4_irq_en) +{ + int i; + int reg_offset = dev_priv->gpio_mmio_base; + u32 gmbus2 = 0; + DEFINE_WAIT(wait); + + if (!HAS_GMBUS_IRQ(dev_priv->dev)) + gmbus4_irq_en = 0; + + /* Important: The hw handles only the first bit, so set only one! Since + * we also need to check for NAKs besides the hw ready/idle signal, we + * need to wake up periodically and check that ourselves. */ + I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en); + + for (i = 0; i < msecs_to_jiffies(50) + 1; i++) { + prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait, + TASK_UNINTERRUPTIBLE); + + gmbus2 = I915_READ_NOTRACE(GMBUS2 + reg_offset); + if (gmbus2 & (GMBUS_SATOER | gmbus2_status)) + break; + + schedule_timeout(1); + } + finish_wait(&dev_priv->gmbus_wait_queue, &wait); + + I915_WRITE(GMBUS4 + reg_offset, 0); + + if (gmbus2 & GMBUS_SATOER) + return -ENXIO; + if (gmbus2 & gmbus2_status) + return 0; + return -ETIMEDOUT; } static int -intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) +gmbus_wait_idle(struct drm_i915_private *dev_priv) +{ + int ret; + int reg_offset = dev_priv->gpio_mmio_base; + +#define C ((I915_READ_NOTRACE(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0) + + if (!HAS_GMBUS_IRQ(dev_priv->dev)) + return wait_for(C, 10); + + /* Important: The hw handles only the first bit, so set only one! */ + I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN); + + ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10); + + I915_WRITE(GMBUS4 + reg_offset, 0); + + if (ret) + return 0; + else + return -ETIMEDOUT; +#undef C +} + +static int +gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, + u32 gmbus1_index) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u16 len = msg->len; + u8 *buf = msg->buf; + + I915_WRITE(GMBUS1 + reg_offset, + gmbus1_index | + GMBUS_CYCLE_WAIT | + (len << GMBUS_BYTE_COUNT_SHIFT) | + (msg->slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | + GMBUS_SLAVE_READ | GMBUS_SW_RDY); + while (len) { + int ret; + u32 val, loop = 0; + + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, + GMBUS_HW_RDY_EN); + if (ret) + return ret; + + val = I915_READ(GMBUS3 + reg_offset); + do { + *buf++ = val & 0xff; + val >>= 8; + } while (--len && ++loop < 4); + } + + return 0; +} + +static int +gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u16 len = msg->len; + u8 *buf = msg->buf; + u32 val, loop; + + val = loop = 0; + while (len && loop < 4) { + val |= *buf++ << (8 * loop++); + len -= 1; + } + + I915_WRITE(GMBUS3 + reg_offset, val); + I915_WRITE(GMBUS1 + reg_offset, + GMBUS_CYCLE_WAIT | + (msg->len << GMBUS_BYTE_COUNT_SHIFT) | + (msg->slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | + GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); + while (len) { + int ret; + + val = loop = 0; + do { + val |= *buf++ << (8 * loop); + } while (--len && ++loop < 4); + + I915_WRITE(GMBUS3 + reg_offset, val); + + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_RDY, + GMBUS_HW_RDY_EN); + if (ret) + return ret; + } + return 0; +} + +/* + * The gmbus controller can combine a 1 or 2 byte write with a read that + * immediately follows it by using an "INDEX" cycle. + */ +static bool +gmbus_is_index_read(struct i2c_msg *msgs, int i, int num) +{ + return (i + 1 < num && + !(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 && + (msgs[i + 1].flags & I2C_M_RD)); +} + +static int +gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) +{ + int reg_offset = dev_priv->gpio_mmio_base; + u32 gmbus1_index = 0; + u32 gmbus5 = 0; + int ret; + + if (msgs[0].len == 2) + gmbus5 = GMBUS_2BYTE_INDEX_EN | + msgs[0].buf[1] | (msgs[0].buf[0] << 8); + if (msgs[0].len == 1) + gmbus1_index = GMBUS_CYCLE_INDEX | + (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT); + + /* GMBUS5 holds 16-bit index */ + if (gmbus5) + I915_WRITE(GMBUS5 + reg_offset, gmbus5); + + ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index); + + /* Clear GMBUS5 after each index transfer */ + if (gmbus5) + I915_WRITE(GMBUS5 + reg_offset, 0); + + return ret; +} + +static int +gmbus_xfer(struct device *adapter, + struct i2c_msg *msgs, + int num) { struct intel_iic_softc *sc; struct drm_i915_private *dev_priv; - u8 *buf; - int error, i, reg_offset, unit; - u32 val, loop; - u16 len; + int i, reg_offset, unit; + int ret = 0; - sc = device_get_softc(idev); + sc = device_get_softc(adapter); dev_priv = sc->drm_dev->dev_private; - unit = device_get_unit(idev); + unit = device_get_unit(adapter); + + mutex_lock(&dev_priv->gmbus_mutex); - lockmgr(&dev_priv->gmbus_mutex, LK_EXCLUSIVE); if (sc->force_bit_dev) { - error = intel_iic_quirk_xfer(dev_priv->bbbus[unit], msgs, nmsgs); + ret = intel_i2c_quirk_xfer(dev_priv->bbbus[unit], msgs, num); goto out; } @@ -240,115 +503,95 @@ intel_gmbus_transfer(device_t idev, struct iic_msg *msgs, uint32_t nmsgs) I915_WRITE(GMBUS0 + reg_offset, sc->reg0); - for (i = 0; i < nmsgs; i++) { - len = msgs[i].len; - buf = msgs[i].buf; - - if ((msgs[i].flags & IIC_M_RD) != 0) { - I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (i + 1 == nmsgs ? GMBUS_CYCLE_STOP : 0) | - (len << GMBUS_BYTE_COUNT_SHIFT) | - (msgs[i].slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | - GMBUS_SLAVE_READ | GMBUS_SW_RDY); - POSTING_READ(GMBUS2 + reg_offset); - do { - loop = 0; - - if (_intel_wait_for(sc->drm_dev, - (I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY)) != 0, - 50, 1, "915gbr")) - goto timeout; - if ((I915_READ(GMBUS2 + reg_offset) & - GMBUS_SATOER) != 0) - goto clear_err; - - val = I915_READ(GMBUS3 + reg_offset); - do { - *buf++ = val & 0xff; - val >>= 8; - } while (--len != 0 && ++loop < 4); - } while (len != 0); + for (i = 0; i < num; i++) { + if (gmbus_is_index_read(msgs, i, num)) { + ret = gmbus_xfer_index_read(dev_priv, &msgs[i]); + i += 1; /* set i to the index of the read xfer */ + } else if (msgs[i].flags & I2C_M_RD) { + ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); } else { - val = loop = 0; - do { - val |= *buf++ << (8 * loop); - } while (--len != 0 && ++loop < 4); - - I915_WRITE(GMBUS3 + reg_offset, val); - I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (i + 1 == nmsgs ? GMBUS_CYCLE_STOP : 0) | - (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) | - (msgs[i].slave << (GMBUS_SLAVE_ADDR_SHIFT - 1)) | - GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); - POSTING_READ(GMBUS2+reg_offset); - - while (len != 0) { - if (_intel_wait_for(sc->drm_dev, - (I915_READ(GMBUS2 + reg_offset) & - (GMBUS_SATOER | GMBUS_HW_RDY)) != 0, - 50, 1, "915gbw")) - goto timeout; - if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) - goto clear_err; - - val = loop = 0; - do { - val |= *buf++ << (8 * loop); - } while (--len != 0 && ++loop < 4); - - I915_WRITE(GMBUS3 + reg_offset, val); - POSTING_READ(GMBUS2 + reg_offset); - } + ret = gmbus_xfer_write(dev_priv, &msgs[i]); } - if (i + 1 < nmsgs && _intel_wait_for(sc->drm_dev, - (I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | - GMBUS_HW_WAIT_PHASE)) != 0, - 50, 1, "915gbh")) + if (ret == -ETIMEDOUT) goto timeout; - if ((I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) != 0) + if (ret == -ENXIO) goto clear_err; + + ret = gmbus_wait_hw_status(dev_priv, GMBUS_HW_WAIT_PHASE, + GMBUS_HW_WAIT_EN); + if (ret == -ENXIO) + goto clear_err; + if (ret) + goto timeout; } - error = 0; -done: + /* Generate a STOP condition on the bus. Note that gmbus can't generata + * a STOP on the very first cycle. To simplify the code we + * unconditionally generate the STOP condition with an additional gmbus + * cycle. */ + I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY); + /* Mark the GMBUS interface as disabled after waiting for idle. * We will re-enable it at the start of the next xfer, * till then let it sleep. - */ - if (_intel_wait_for(dev, - (I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, - 10, 1, "915gbu")) - DRM_INFO("GMBUS timed out waiting for idle\n"); + */ + if (gmbus_wait_idle(dev_priv)) { + DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n", + sc->name); + ret = -ETIMEDOUT; + } I915_WRITE(GMBUS0 + reg_offset, 0); -out: - lockmgr(&dev_priv->gmbus_mutex, LK_RELEASE); - return (error); + ret = ret ?: i; + goto timeout; /* XXX: should be out */ clear_err: + /* + * Wait for bus to IDLE before clearing NAK. + * If we clear the NAK while bus is still active, then it will stay + * active and the next transaction may fail. + * + * If no ACK is received during the address phase of a transaction, the + * adapter must report -ENXIO. It is not clear what to return if no ACK + * is received at other times. But we have to be careful to not return + * spurious -ENXIO because that will prevent i2c and drm edid functions + * from retrying. So return -ENXIO only when gmbus properly quiescents - + * timing out seems to happen when there _is_ a ddc chip present, but + * it's slow responding and only answers on the 2nd retry. + */ + ret = -ENXIO; + if (gmbus_wait_idle(dev_priv)) { + DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n", + sc->name); + ret = -ETIMEDOUT; + } + /* Toggle the Software Clear Interrupt bit. This has the effect * of resetting the GMBUS controller and so clearing the * BUS_ERROR raised by the slave's NAK. */ I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); I915_WRITE(GMBUS1 + reg_offset, 0); - error = EIO; - goto done; + I915_WRITE(GMBUS0 + reg_offset, 0); + + DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n", + sc->name, msgs[i].slave, + (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len); + + goto out; timeout: - DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", - sc->reg0 & 0xff, sc->name); + DRM_INFO("GMBUS [%s] timed out, falling back to bit banging on pin %d\n", + sc->name, sc->reg0 & 0xff); I915_WRITE(GMBUS0 + reg_offset, 0); - /* - * Hardware may not support GMBUS over these pins? - * Try GPIO bitbanging instead. - */ + /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ sc->force_bit_dev = true; + ret = intel_i2c_quirk_xfer(dev_priv->bbbus[unit], msgs, num); - error = intel_iic_quirk_xfer(dev_priv->bbbus[unit], msgs, nmsgs); - goto out; +out: + mutex_unlock(&dev_priv->gmbus_mutex); + return ret; } struct device *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv, @@ -376,49 +619,12 @@ intel_gmbus_force_bit(device_t idev, bool force_bit) struct intel_iic_softc *sc; sc = device_get_softc(device_get_parent(idev)); - sc->force_bit_dev = force_bit; + sc->force_bit_dev += force_bit ? 1 : -1; + DRM_DEBUG_KMS("%sabling bit-banging on %s. force bit now %d\n", + force_bit ? "en" : "dis", sc->name, + sc->force_bit_dev); } -static int -intel_iic_quirk_xfer(device_t idev, struct iic_msg *msgs, int nmsgs) -{ - device_t bridge_dev; - struct intel_iic_softc *sc; - struct drm_i915_private *dev_priv; - int ret; - int i; - - bridge_dev = device_get_parent(device_get_parent(idev)); - sc = device_get_softc(bridge_dev); - dev_priv = sc->drm_dev->dev_private; - - intel_i2c_reset(sc->drm_dev); - intel_iic_quirk_set(dev_priv, true); - IICBB_SETSDA(bridge_dev, 1); - IICBB_SETSCL(bridge_dev, 1); - DELAY(I2C_RISEFALL_TIME); - - for (i = 0; i < nmsgs - 1; i++) { - /* force use of repeated start instead of default stop+start */ - msgs[i].flags |= IIC_M_NOSTOP; - } - ret = iicbus_transfer(idev, msgs, nmsgs); - IICBB_SETSDA(bridge_dev, 1); - IICBB_SETSCL(bridge_dev, 1); - intel_iic_quirk_set(dev_priv, false); - - return (ret); -} - -static const char *gpio_names[GMBUS_NUM_PORTS] = { - "ssc", - "vga", - "panel", - "dpc", - "dpb", - "dpd", -}; - static int intel_gmbus_probe(device_t dev) { @@ -486,47 +692,6 @@ intel_iicbb_probe(device_t dev) return (BUS_PROBE_DEFAULT); } -static int -intel_iicbb_attach(device_t idev) -{ - static const int map_pin_to_reg[] = { - 0, - GPIOB, - GPIOA, - GPIOC, - GPIOD, - GPIOE, - GPIOF, - 0 - }; - - struct intel_iic_softc *sc; - struct drm_i915_private *dev_priv; - int pin; - - sc = device_get_softc(idev); - sc->drm_dev = device_get_softc(device_get_parent(idev)); - dev_priv = sc->drm_dev->dev_private; - pin = device_get_unit(idev); - - ksnprintf(sc->name, sizeof(sc->name), "i915 iicbb %s", gpio_names[pin]); - device_set_desc(idev, sc->name); - - sc->reg0 = (pin + 1) | GMBUS_RATE_100KHZ; - sc->reg = map_pin_to_reg[pin + 1]; - if (HAS_PCH_SPLIT(dev_priv->dev)) - sc->reg += PCH_GPIOA - GPIOA; - - /* add generic bit-banging code */ - sc->iic_dev = device_add_child(idev, "iicbb", -1); - if (sc->iic_dev == NULL) - return (ENXIO); - device_quiet(sc->iic_dev); - bus_generic_attach(idev); - - return (0); -} - static int intel_iicbb_detach(device_t idev) { @@ -546,7 +711,7 @@ static device_method_t intel_gmbus_methods[] = { DEVMETHOD(device_attach, intel_gmbus_attach), DEVMETHOD(device_detach, intel_gmbus_detach), DEVMETHOD(iicbus_reset, intel_iicbus_reset), - DEVMETHOD(iicbus_transfer, intel_gmbus_transfer), + DEVMETHOD(iicbus_transfer, gmbus_xfer), DEVMETHOD_END }; static driver_t intel_gmbus_driver = { @@ -561,7 +726,7 @@ DRIVER_MODULE(iicbus, intel_gmbus, iicbus_driver, iicbus_devclass, NULL, NULL); static device_method_t intel_iicbb_methods[] = { DEVMETHOD(device_probe, intel_iicbb_probe), - DEVMETHOD(device_attach, intel_iicbb_attach), + DEVMETHOD(device_attach, intel_gpio_setup), DEVMETHOD(device_detach, intel_iicbb_detach), DEVMETHOD(bus_add_child, bus_generic_add_child), @@ -569,10 +734,10 @@ static device_method_t intel_iicbb_methods[] = { DEVMETHOD(iicbb_callback, iicbus_null_callback), DEVMETHOD(iicbb_reset, intel_iicbus_reset), - DEVMETHOD(iicbb_setsda, intel_iicbb_setsda), - DEVMETHOD(iicbb_setscl, intel_iicbb_setscl), - DEVMETHOD(iicbb_getsda, intel_iicbb_getsda), - DEVMETHOD(iicbb_getscl, intel_iicbb_getscl), + DEVMETHOD(iicbb_setsda, set_data), + DEVMETHOD(iicbb_setscl, set_clock), + DEVMETHOD(iicbb_getsda, get_data), + DEVMETHOD(iicbb_getscl, get_clock), DEVMETHOD_END }; static driver_t intel_iicbb_driver = { @@ -585,15 +750,25 @@ DRIVER_MODULE_ORDERED(intel_iicbb, drm, intel_iicbb_driver, intel_iicbb_devclass, 0, 0, SI_ORDER_FIRST); DRIVER_MODULE(iicbb, intel_iicbb, iicbb_driver, iicbb_devclass, NULL, NULL); +static void intel_teardown_gmbus_m(struct drm_device *dev, int m); + int intel_setup_gmbus(struct drm_device *dev) { - struct drm_i915_private *dev_priv; + struct drm_i915_private *dev_priv = dev->dev_private; device_t iic_dev; int i, ret; - dev_priv = dev->dev_private; + if (HAS_PCH_SPLIT(dev)) + dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; + else if (IS_VALLEYVIEW(dev)) + dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; + else + dev_priv->gpio_mmio_base = 0; + lockinit(&dev_priv->gmbus_mutex, "gmbus", 0, LK_CANRECURSE); + init_waitqueue_head(&dev_priv->gmbus_wait_queue); + dev_priv->gmbus_bridge = kmalloc(sizeof(device_t) * GMBUS_NUM_PORTS, M_DRM, M_WAITOK | M_ZERO); dev_priv->bbbus_bridge = kmalloc(sizeof(device_t) * GMBUS_NUM_PORTS, diff --git a/sys/dev/drm/i915/intel_lvds.c b/sys/dev/drm/i915/intel_lvds.c index 0c2df09c02..f49644bf58 100644 --- a/sys/dev/drm/i915/intel_lvds.c +++ b/sys/dev/drm/i915/intel_lvds.c @@ -27,13 +27,13 @@ * Jesse Barnes */ +#include #include #include #include #include "intel_drv.h" #include #include "i915_drv.h" -#include /* Private structure for the integrated LVDS support */ struct intel_lvds_connector { @@ -49,7 +49,8 @@ struct intel_lvds_encoder { u32 pfit_control; u32 pfit_pgm_ratios; - bool pfit_dirty; + bool is_dual_link; + u32 reg; struct intel_lvds_connector *attached_connector; }; @@ -69,15 +70,10 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 lvds_reg, tmp; - - if (HAS_PCH_SPLIT(dev)) { - lvds_reg = PCH_LVDS; - } else { - lvds_reg = LVDS; - } + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + u32 tmp; - tmp = I915_READ(lvds_reg); + tmp = I915_READ(lvds_encoder->reg); if (!(tmp & LVDS_PORT_EN)) return false; @@ -90,6 +86,91 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder, return true; } +/* The LVDS pin pair needs to be on before the DPLLs are enabled. + * This is an exception to the general rule that mode_set doesn't turn + * things on. + */ +static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder) +{ + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct drm_display_mode *fixed_mode = + lvds_encoder->attached_connector->base.panel.fixed_mode; + int pipe = intel_crtc->pipe; + u32 temp; + + temp = I915_READ(lvds_encoder->reg); + temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP; + + if (HAS_PCH_CPT(dev)) { + temp &= ~PORT_TRANS_SEL_MASK; + temp |= PORT_TRANS_SEL_CPT(pipe); + } else { + if (pipe == 1) { + temp |= LVDS_PIPEB_SELECT; + } else { + temp &= ~LVDS_PIPEB_SELECT; + } + } + + /* set the corresponsding LVDS_BORDER bit */ + temp |= dev_priv->lvds_border_bits; + /* Set the B0-B3 data pairs corresponding to whether we're going to + * set the DPLLs for dual-channel mode or not. + */ + if (lvds_encoder->is_dual_link) + temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP; + else + temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP); + + /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP) + * appropriately here, but we need to look more thoroughly into how + * panels behave in the two modes. + */ + + /* Set the dithering flag on LVDS as needed, note that there is no + * special lvds dither control bit on pch-split platforms, dithering is + * only controlled through the PIPECONF reg. */ + if (INTEL_INFO(dev)->gen == 4) { + if (dev_priv->lvds_dither) + temp |= LVDS_ENABLE_DITHER; + else + temp &= ~LVDS_ENABLE_DITHER; + } + temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY); + if (fixed_mode->flags & DRM_MODE_FLAG_NHSYNC) + temp |= LVDS_HSYNC_POLARITY; + if (fixed_mode->flags & DRM_MODE_FLAG_NVSYNC) + temp |= LVDS_VSYNC_POLARITY; + + I915_WRITE(lvds_encoder->reg, temp); +} + +static void intel_pre_enable_lvds(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base); + struct drm_i915_private *dev_priv = dev->dev_private; + + if (HAS_PCH_SPLIT(dev) || !enc->pfit_control) + return; + + /* + * Enable automatic panel scaling so that non-native modes + * fill the screen. The panel fitter should only be + * adjusted whilst the pipe is disabled, according to + * register description and PRM. + */ + DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", + enc->pfit_control, + enc->pfit_pgm_ratios); + + I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios); + I915_WRITE(PFIT_CONTROL, enc->pfit_control); +} + /** * Sets the power state for the panel. */ @@ -99,38 +180,20 @@ static void intel_enable_lvds(struct intel_encoder *encoder) struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, lvds_reg, stat_reg; + u32 ctl_reg, stat_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; - lvds_reg = PCH_LVDS; stat_reg = PCH_PP_STATUS; } else { ctl_reg = PP_CONTROL; - lvds_reg = LVDS; stat_reg = PP_STATUS; } - I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); - - if (lvds_encoder->pfit_dirty) { - /* - * Enable automatic panel scaling so that non-native modes - * fill the screen. The panel fitter should only be - * adjusted whilst the pipe is disabled, according to - * register description and PRM. - */ - DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n", - lvds_encoder->pfit_control, - lvds_encoder->pfit_pgm_ratios); - - I915_WRITE(PFIT_PGM_RATIOS, lvds_encoder->pfit_pgm_ratios); - I915_WRITE(PFIT_CONTROL, lvds_encoder->pfit_control); - lvds_encoder->pfit_dirty = false; - } + I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) | LVDS_PORT_EN); I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON); - POSTING_READ(lvds_reg); + POSTING_READ(lvds_encoder->reg); if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000)) DRM_ERROR("timed out waiting for panel to power on\n"); @@ -142,15 +205,13 @@ static void intel_disable_lvds(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, lvds_reg, stat_reg; + u32 ctl_reg, stat_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; - lvds_reg = PCH_LVDS; stat_reg = PCH_PP_STATUS; } else { ctl_reg = PP_CONTROL; - lvds_reg = LVDS; stat_reg = PP_STATUS; } @@ -160,13 +221,8 @@ static void intel_disable_lvds(struct intel_encoder *encoder) if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); - if (lvds_encoder->pfit_control) { - I915_WRITE(PFIT_CONTROL, 0); - lvds_encoder->pfit_dirty = true; - } - - I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN); - POSTING_READ(lvds_reg); + I915_WRITE(lvds_encoder->reg, I915_READ(lvds_encoder->reg) & ~LVDS_PORT_EN); + POSTING_READ(lvds_encoder->reg); } static int intel_lvds_mode_valid(struct drm_connector *connector, @@ -404,7 +460,6 @@ out: pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) { lvds_encoder->pfit_control = pfit_control; lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios; - lvds_encoder->pfit_dirty = true; } dev_priv->lvds_border_bits = border; @@ -491,13 +546,14 @@ static const struct dmi_system_id intel_no_modeset_on_lid[] = { #if 0 /* - * Lid events. Note the use of 'modeset_on_lid': - * - we set it on lid close, and reset it on open + * Lid events. Note the use of 'modeset': + * - we set it to MODESET_ON_LID_OPEN on lid close, + * and set it to MODESET_DONE on open * - we use it as a "only once" bit (ie we ignore - * duplicate events where it was already properly - * set/reset) - * - the suspend/resume paths will also set it to - * zero, since they restore the mode ("lid open"). + * duplicate events where it was already properly set) + * - the suspend/resume paths will set it to + * MODESET_SUSPENDED and ignore the lid open event, + * because they restore the mode ("lid open"). */ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, void *unused) @@ -511,6 +567,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, if (dev->switch_power_state != DRM_SWITCH_POWER_ON) return NOTIFY_OK; + mutex_lock(&dev_priv->modeset_restore_lock); + if (dev_priv->modeset_restore == MODESET_SUSPENDED) + goto exit; /* * check and update the status of LVDS connector after receiving * the LID nofication event. @@ -519,21 +578,24 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, /* Don't force modeset on machines where it causes a GPU lockup */ if (dmi_check_system(intel_no_modeset_on_lid)) - return NOTIFY_OK; + goto exit; if (!acpi_lid_open()) { - dev_priv->modeset_on_lid = 1; - return NOTIFY_OK; + /* do modeset on next lid open event */ + dev_priv->modeset_restore = MODESET_ON_LID_OPEN; + goto exit; } - if (!dev_priv->modeset_on_lid) - return NOTIFY_OK; - - dev_priv->modeset_on_lid = 0; + if (dev_priv->modeset_restore == MODESET_DONE) + goto exit; - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, true); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); + + dev_priv->modeset_restore = MODESET_DONE; +exit: + mutex_unlock(&dev_priv->modeset_restore_lock); return NOTIFY_OK; } #endif @@ -594,8 +656,7 @@ static int intel_lvds_set_property(struct drm_connector *connector, * If the CRTC is enabled, the display will be changed * according to the new panel fitting mode. */ - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + intel_crtc_restore_mode(crtc); } } @@ -605,7 +666,6 @@ static int intel_lvds_set_property(struct drm_connector *connector, static const struct drm_encoder_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, .mode_set = intel_lvds_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = { @@ -626,7 +686,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = { .destroy = intel_encoder_destroy, }; -static int intel_no_lvds_dmi_callback(const struct dmi_system_id *id) +static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id) { DRM_INFO("Skipping LVDS initialization for %s\n", id->ident); return 1; @@ -747,10 +807,10 @@ static const struct dmi_system_id intel_no_lvds[] = { }, { .callback = intel_no_lvds_dmi_callback, - .ident = "Hewlett-Packard HP t5740e Thin Client", + .ident = "Hewlett-Packard HP t5740", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"), + DMI_MATCH(DMI_PRODUCT_NAME, " t5740"), }, }, { @@ -906,6 +966,66 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, return false; } +static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) +{ + DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident); + return 1; +} + +static const struct dmi_system_id intel_dual_link_lvds[] = { + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro (Core i5/i7 Series)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), + }, + }, + { } /* terminating entry */ +}; + +bool intel_is_dual_link_lvds(struct drm_device *dev) +{ + struct intel_encoder *encoder; + struct intel_lvds_encoder *lvds_encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, + base.head) { + if (encoder->type == INTEL_OUTPUT_LVDS) { + lvds_encoder = to_lvds_encoder(&encoder->base); + + return lvds_encoder->is_dual_link; + } + } + + return false; +} + +static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) +{ + struct drm_device *dev = lvds_encoder->base.base.dev; + unsigned int val; + struct drm_i915_private *dev_priv = dev->dev_private; + + /* use the module option value if specified */ + if (i915_lvds_channel_mode > 0) + return i915_lvds_channel_mode == 2; + + if (dmi_check_system(intel_dual_link_lvds)) + return true; + + /* BIOS should set the proper LVDS register value at boot, but + * in reality, it doesn't set the value when the lid is closed; + * we need to check "the value to be set" in VBT when LVDS + * register is uninitialized. + */ + val = I915_READ(lvds_encoder->reg); + if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED))) + val = dev_priv->bios_lvds_val; + + return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; +} + static bool intel_lvds_supported(struct drm_device *dev) { /* With the introduction of the PCH we gained a dedicated @@ -993,6 +1113,8 @@ bool intel_lvds_init(struct drm_device *dev) DRM_MODE_ENCODER_LVDS); intel_encoder->enable = intel_enable_lvds; + intel_encoder->pre_enable = intel_pre_enable_lvds; + intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds; intel_encoder->disable = intel_disable_lvds; intel_encoder->get_hw_state = intel_lvds_get_hw_state; intel_connector->get_hw_state = intel_connector_get_hw_state; @@ -1014,9 +1136,14 @@ bool intel_lvds_init(struct drm_device *dev) connector->interlace_allowed = false; connector->doublescan_allowed = false; + if (HAS_PCH_SPLIT(dev)) { + lvds_encoder->reg = PCH_LVDS; + } else { + lvds_encoder->reg = LVDS; + } + /* create the scaling mode property */ drm_mode_create_scaling_mode_property(dev); - drm_object_attach_property(&connector->base, dev->mode_config.scaling_mode_property, DRM_MODE_SCALE_ASPECT); @@ -1115,6 +1242,10 @@ bool intel_lvds_init(struct drm_device *dev) goto failed; out: + lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder); + DRM_DEBUG_KMS("detected %s-link lvds configuration\n", + lvds_encoder->is_dual_link ? "dual" : "single"); + /* * Unlock registers and just * leave them unlocked diff --git a/sys/dev/drm/i915/intel_modes.c b/sys/dev/drm/i915/intel_modes.c index c32b220832..94af089176 100644 --- a/sys/dev/drm/i915/intel_modes.c +++ b/sys/dev/drm/i915/intel_modes.c @@ -24,11 +24,10 @@ */ #include -#include #include +#include #include "intel_drv.h" #include "i915_drv.h" -#include /** * intel_connector_update_modes - update connector from edid @@ -99,8 +98,9 @@ intel_attach_force_audio_property(struct drm_connector *connector) } static const struct drm_prop_enum_list broadcast_rgb_names[] = { - { 0, "Full" }, - { 1, "Limited 16:235" }, + { INTEL_BROADCAST_RGB_AUTO, "Automatic" }, + { INTEL_BROADCAST_RGB_FULL, "Full" }, + { INTEL_BROADCAST_RGB_LIMITED, "Limited 16:235" }, }; void diff --git a/sys/dev/drm/i915/intel_opregion.c b/sys/dev/drm/i915/intel_opregion.c index 0aa5e38976..df1f4ed45e 100644 --- a/sys/dev/drm/i915/intel_opregion.c +++ b/sys/dev/drm/i915/intel_opregion.c @@ -29,6 +29,7 @@ #include #include "i915_drv.h" #include "intel_drv.h" + #include #include #include @@ -346,8 +347,8 @@ static void intel_didl_outputs(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_opregion *opregion = &dev_priv->opregion; struct drm_connector *connector; + ACPI_HANDLE handle, acpi_cdev, acpi_video_bus; u32 device_id; - ACPI_HANDLE handle, acpi_video_bus, acpi_cdev; ACPI_STATUS status; u32 temp; int i = 0; @@ -379,17 +380,20 @@ static void intel_didl_outputs(struct drm_device *dev) while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpi_video_bus, acpi_cdev, &acpi_cdev) != AE_NOT_FOUND) { if (i >= 8) { - device_printf(dev->dev, "More than 8 outputs detected\n"); + device_printf(dev->dev, + "More than 8 outputs detected\n"); return; } status = acpi_GetInteger(acpi_cdev, "_ADR", &device_id); if (ACPI_SUCCESS(status)) { if (!device_id) goto blind_set; - opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f); + iowrite32((u32)(device_id & 0x0f0f), + &opregion->acpi->didl[i]); i++; } } + end: /* If fewer than 8 outputs, the list must be null terminated */ if (i < 8) diff --git a/sys/dev/drm/i915/intel_overlay.c b/sys/dev/drm/i915/intel_overlay.c index a15ec8d0a9..c7bb232488 100644 --- a/sys/dev/drm/i915/intel_overlay.c +++ b/sys/dev/drm/i915/intel_overlay.c @@ -1045,13 +1045,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, } if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) { - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); - DRM_LOCK(dev); + drm_modeset_lock_all(dev); + mutex_lock(&dev->struct_mutex); ret = intel_overlay_switch_off(overlay); - DRM_UNLOCK(dev); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + mutex_unlock(&dev->struct_mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1076,8 +1076,8 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, goto out_free; } - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); - DRM_LOCK(dev); + drm_modeset_lock_all(dev); + mutex_lock(&dev->struct_mutex); if (new_bo->tiling_mode) { DRM_ERROR("buffer used for overlay image can not be tiled\n"); @@ -1157,16 +1157,16 @@ int intel_overlay_put_image(struct drm_device *dev, void *data, if (ret != 0) goto out_unlock; - DRM_UNLOCK(dev); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + mutex_unlock(&dev->struct_mutex); + drm_modeset_unlock_all(dev); kfree(params, M_DRM); return 0; out_unlock: - DRM_UNLOCK(dev); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + mutex_unlock(&dev->struct_mutex); + drm_modeset_unlock_all(dev); drm_gem_object_unreference_unlocked(&new_bo->base); out_free: kfree(params, M_DRM); @@ -1242,8 +1242,8 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, return -ENODEV; } - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); - DRM_LOCK(dev); + drm_modeset_lock_all(dev); + mutex_lock(&dev->struct_mutex); ret = -EINVAL; if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) { @@ -1307,8 +1307,8 @@ int intel_overlay_attrs(struct drm_device *dev, void *data, ret = 0; out_unlock: - DRM_UNLOCK(dev); - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + mutex_unlock(&dev->struct_mutex); + drm_modeset_unlock_all(dev); return ret; } @@ -1329,7 +1329,7 @@ void intel_setup_overlay(struct drm_device *dev) if (!overlay) return; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); if (WARN_ON(dev_priv->overlay)) goto out_free; @@ -1381,7 +1381,7 @@ void intel_setup_overlay(struct drm_device *dev) intel_overlay_unmap_regs(overlay, regs); dev_priv->overlay = overlay; - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); DRM_INFO("initialized overlay support\n"); return; @@ -1391,7 +1391,7 @@ out_unpin_bo: out_free_bo: drm_gem_object_unreference(®_bo->base); out_free: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); kfree(overlay, M_DRM); return; } @@ -1434,7 +1434,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay) regs = (struct overlay_registers __iomem *) overlay->reg_bo->phys_obj->handle->vaddr; else - regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, + regs = io_mapping_map_atomic_wc(dev_priv->gtt.mappable, overlay->reg_bo->gtt_offset); return regs; diff --git a/sys/dev/drm/i915/intel_panel.c b/sys/dev/drm/i915/intel_panel.c index 436b598e31..1715074121 100644 --- a/sys/dev/drm/i915/intel_panel.c +++ b/sys/dev/drm/i915/intel_panel.c @@ -28,9 +28,9 @@ * Chris Wilson */ -#include -#include +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include "intel_drv.h" #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ @@ -206,14 +206,12 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) static int i915_panel_invert_brightness; TUNABLE_INT("drm.i915.panel_invert_brightness", &i915_panel_invert_brightness); -#if 0 MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness " "(-1 force normal, 0 machine defaults, 1 force inversion), please " "report PCI device ID, subsystem vendor and subsystem device ID " "to dri-devel@lists.freedesktop.org, if your machine needs it. " "It will then be included in an upcoming module version."); -#endif - +module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600); static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/sys/dev/drm/i915/intel_pm.c b/sys/dev/drm/i915/intel_pm.c index 6de2bbf2ee..b2bc61f77b 100644 --- a/sys/dev/drm/i915/intel_pm.c +++ b/sys/dev/drm/i915/intel_pm.c @@ -25,10 +25,9 @@ * */ -#include -#include "intel_drv.h" #include "i915_drv.h" -#include +#include "intel_drv.h" +#include #include #define FORCEWAKE_ACK_TIMEOUT_MS 2 @@ -271,7 +270,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct drm_device *dev = work->crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); if (work == dev_priv->fbc_work) { /* Double check that we haven't switched fb without cancelling * the prior work. @@ -287,7 +286,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) dev_priv->fbc_work = NULL; } - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); kfree(work, M_DRM); } @@ -447,12 +446,6 @@ void intel_update_fbc(struct drm_device *dev) dev_priv->no_fbc_reason = FBC_MODULE_PARAM; goto out_disable; } - if (intel_fb->obj->base.size > dev_priv->cfb_size) { - DRM_DEBUG_KMS("framebuffer too large, disabling " - "compression\n"); - dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; - goto out_disable; - } if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) || (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) { DRM_DEBUG_KMS("mode incompatible with compression, " @@ -488,6 +481,14 @@ void intel_update_fbc(struct drm_device *dev) goto out_disable; #endif + if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) { + DRM_INFO("not enough stolen space for compressed buffer (need %zd bytes), disabling\n", intel_fb->obj->base.size); + DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n"); + DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); + dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL; + goto out_disable; + } + /* If the scanout has not changed, don't modify the FBC settings. * Note that we make the fundamental assumption that the fb->obj * cannot be unpinned (and have its GTT offset and fence revoked) @@ -535,6 +536,7 @@ out_disable: DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); intel_disable_fbc(dev); } + i915_gem_stolen_cleanup_compression(dev); } static void i915_pineview_get_mem_freq(struct drm_device *dev) @@ -1287,7 +1289,7 @@ static void vlv_update_drain_latency(struct drm_device *dev) } } -#define single_plane_enabled(mask) ((mask) != 0 && powerof2(mask)) +#define single_plane_enabled(mask) is_power_of_2(mask) static void valleyview_update_wm(struct drm_device *dev) { @@ -2262,7 +2264,7 @@ intel_alloc_context_page(struct drm_device *dev) struct drm_i915_gem_object *ctx; int ret; - DRM_LOCK_ASSERT(dev); + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); ctx = i915_gem_alloc_object(dev, 4096); if (!ctx) { @@ -2288,7 +2290,6 @@ err_unpin: i915_gem_object_unpin(ctx); err_unref: drm_gem_object_unreference(&ctx->base); - DRM_UNLOCK(dev); return NULL; } @@ -2300,7 +2301,7 @@ LOCK_SYSINIT(mchdev, &mchdev_lock, "mchdev", LK_CANRECURSE); /* Global for IPS driver to get at the current i915 device. Protected by * mchdev_lock. */ -struct drm_i915_private *i915_mch_dev; +static struct drm_i915_private *i915_mch_dev; bool ironlake_set_drps(struct drm_device *dev, u8 val) { @@ -2379,7 +2380,7 @@ static void ironlake_enable_drps(struct drm_device *dev) if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) DRM_ERROR("stuck trying to change perf mode\n"); - DELAY(1000); + mdelay(1); ironlake_set_drps(dev, fstart); @@ -2387,7 +2388,7 @@ static void ironlake_enable_drps(struct drm_device *dev) I915_READ(0x112e0); dev_priv->ips.last_time1 = jiffies_to_msecs(jiffies); dev_priv->ips.last_count2 = I915_READ(0x112f4); - nanotime(&dev_priv->ips.last_time2); + getrawmonotonic(&dev_priv->ips.last_time2); lockmgr(&mchdev_lock, LK_RELEASE); } @@ -2397,7 +2398,7 @@ static void ironlake_disable_drps(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u16 rgvswctl; - lockmgr(&mchdev_lock, LK_RELEASE); + lockmgr(&mchdev_lock, LK_EXCLUSIVE); rgvswctl = I915_READ16(MEMSWCTL); @@ -2410,10 +2411,10 @@ static void ironlake_disable_drps(struct drm_device *dev) /* Go back to the starting frequency */ ironlake_set_drps(dev, dev_priv->ips.fstart); - DELAY(1000); + mdelay(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); - DELAY(1000); + mdelay(1); lockmgr(&mchdev_lock, LK_RELEASE); } @@ -2452,6 +2453,7 @@ void gen6_set_rps(struct drm_device *dev, u8 val) struct drm_i915_private *dev_priv = dev->dev_private; u32 limits = gen6_rps_limits(dev_priv, &val); + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); WARN_ON(val > dev_priv->rps.max_delay); WARN_ON(val < dev_priv->rps.min_delay); @@ -2471,6 +2473,8 @@ void gen6_set_rps(struct drm_device *dev, u8 val) POSTING_READ(GEN6_RPNSWREQ); dev_priv->rps.cur_delay = val; + + trace_intel_gpu_freq_change(val * 50); } static void gen6_disable_rps(struct drm_device *dev) @@ -2529,6 +2533,8 @@ static void gen6_enable_rps(struct drm_device *dev) int rc6_mode; int i, ret; + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + /* Here begins a magic sequence of register writes to enable * auto-downclocking. * @@ -2669,6 +2675,8 @@ static void gen6_update_ring_freq(struct drm_device *dev) unsigned int ia_freq, max_ia_freq; int scaling_factor = 180; + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + #if 0 max_ia_freq = cpufreq_quick_get_max(0); /* @@ -2701,11 +2709,7 @@ static void gen6_update_ring_freq(struct drm_device *dev) ia_freq = 800; else ia_freq = max_ia_freq - ((diff * scaling_factor) / 2); -#if 0 ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100); -#else - ia_freq = (ia_freq + 50) / 100; -#endif ia_freq <<= GEN6_PCODE_FREQ_IA_RATIO_SHIFT; sandybridge_pcode_write(dev_priv, @@ -2781,6 +2785,8 @@ static void ironlake_enable_rc6(struct drm_device *dev) if (!intel_enable_rc6(dev)) return; + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + ret = ironlake_setup_rc6(dev); if (ret) return; @@ -2819,7 +2825,7 @@ static void ironlake_enable_rc6(struct drm_device *dev) ret = intel_ring_idle(ring); dev_priv->mm.interruptible = was_interruptible; if (ret) { - DRM_ERROR("failed to enable ironlake power savings\n"); + DRM_ERROR("failed to enable ironlake power power savings\n"); ironlake_teardown_rc6(dev); return; } @@ -2897,9 +2903,9 @@ static unsigned long __i915_chipset_val(struct drm_i915_private *dev_priv) } } - diff = diff / diff1; + diff = div_u64(diff, diff1); ret = ((m * diff) + c); - ret = ret / 10; + ret = div_u64(ret, 10); dev_priv->ips.last_count1 = total_count; dev_priv->ips.last_time1 = now; @@ -3088,9 +3094,8 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) unsigned long diffms; u32 count; - nanotime(&now); - diff1 = now; - timespecsub(&diff1, &dev_priv->ips.last_time2); + getrawmonotonic(&now); + diff1 = timespec_sub(now, dev_priv->ips.last_time2); /* Don't divide by 0 */ diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000; @@ -3111,7 +3116,7 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv) /* More magic constants... */ diff = diff * 1181; - diff = diff / (diffms * 10); + diff = div_u64(diff, diffms * 10); dev_priv->ips.gfx_power = diff; } @@ -3313,6 +3318,28 @@ out_unlock: return ret; } +#if 0 +/** + * Tells the intel_ips driver that the i915 driver is now loaded, if + * IPS got loaded first. + * + * This awkward dance is so that neither module has to depend on the + * other in order for IPS to do the appropriate communication of + * GPU turbo limits to i915. + */ +static void +ips_ping_for_i915_load(void) +{ + void (*link)(void); + + link = symbol_get(ips_link_to_i915_driver); + if (link) { + link(); + symbol_put(ips_link_to_i915_driver); + } +} +#endif + void intel_gpu_ips_init(struct drm_i915_private *dev_priv) { /* We only register the i915 ips part with intel-ips once everything is @@ -3328,7 +3355,6 @@ void intel_gpu_ips_teardown(void) i915_mch_dev = NULL; lockmgr(&mchdev_lock, LK_RELEASE); } - static void intel_init_emon(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3409,9 +3435,9 @@ void intel_disable_gt_powersave(struct drm_device *dev) ironlake_disable_rc6(dev); } else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) { cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work); - lockmgr(&dev_priv->rps.hw_lock, LK_EXCLUSIVE); + mutex_lock(&dev_priv->rps.hw_lock); gen6_disable_rps(dev); - lockmgr(&dev_priv->rps.hw_lock, LK_RELEASE); + mutex_unlock(&dev_priv->rps.hw_lock); } } @@ -3422,10 +3448,10 @@ static void intel_gen6_powersave_work(struct work_struct *work) rps.delayed_resume_work.work); struct drm_device *dev = dev_priv->dev; - lockmgr(&dev_priv->rps.hw_lock, LK_EXCLUSIVE); + mutex_lock(&dev_priv->rps.hw_lock); gen6_enable_rps(dev); gen6_update_ring_freq(dev); - lockmgr(&dev_priv->rps.hw_lock, LK_RELEASE); + mutex_unlock(&dev_priv->rps.hw_lock); } void intel_enable_gt_powersave(struct drm_device *dev) @@ -3443,7 +3469,7 @@ void intel_enable_gt_powersave(struct drm_device *dev) * to make resume and init faster. */ schedule_delayed_work(&dev_priv->rps.delayed_resume_work, - round_jiffies_up_relative(hz)); + round_jiffies_up_relative(HZ)); } } @@ -3555,6 +3581,19 @@ static void cpt_init_clock_gating(struct drm_device *dev) } } +static void gen6_check_mch_setup(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t tmp; + + tmp = I915_READ(MCH_SSKPD); + if ((tmp & MCH_SSKPD_WM0_MASK) != MCH_SSKPD_WM0_VAL) { + DRM_INFO("Wrong MCH_SSKPD value: 0x%08x\n", tmp); + DRM_INFO("This can cause pipe underruns and display issues.\n"); + DRM_INFO("Please upgrade your BIOS to fix this.\n"); + } +} + static void gen6_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3647,6 +3686,8 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_GT_MODE_HI)); cpt_init_clock_gating(dev); + + gen6_check_mch_setup(dev); } static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) @@ -3658,6 +3699,10 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv) reg |= GEN7_FF_VS_SCHED_HW; reg |= GEN7_FF_DS_SCHED_HW; + /* WaVSRefCountFullforceMissDisable */ + if (IS_HASWELL(dev_priv->dev)) + reg &= ~GEN7_FF_VS_REF_CNT_FFME; + I915_WRITE(GEN7_FF_THREAD_MODE, reg); } @@ -3828,6 +3873,8 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); cpt_init_clock_gating(dev); + + gen6_check_mch_setup(dev); } static void valleyview_init_clock_gating(struct drm_device *dev) @@ -4021,35 +4068,60 @@ void intel_init_clock_gating(struct drm_device *dev) dev_priv->display.init_clock_gating(dev); } -/* Starting with Haswell, we have different power wells for - * different parts of the GPU. This attempts to enable them all. - */ -void intel_init_power_wells(struct drm_device *dev) +void intel_set_power_well(struct drm_device *dev, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long power_wells[] = { - HSW_PWR_WELL_CTL1, - HSW_PWR_WELL_CTL2, - HSW_PWR_WELL_CTL4 - }; - int i; + bool is_enabled, enable_requested; + uint32_t tmp; if (!IS_HASWELL(dev)) return; - DRM_LOCK(dev); + if (!i915_disable_power_well && !enable) + return; - for (i = 0; i < ARRAY_SIZE(power_wells); i++) { - int well = I915_READ(power_wells[i]); + tmp = I915_READ(HSW_PWR_WELL_DRIVER); + is_enabled = tmp & HSW_PWR_WELL_STATE; + enable_requested = tmp & HSW_PWR_WELL_ENABLE; - if ((well & HSW_PWR_WELL_STATE) == 0) { - I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE); - if (wait_for((I915_READ(power_wells[i]) & HSW_PWR_WELL_STATE), 20)) - DRM_ERROR("Error enabling power well %lx\n", power_wells[i]); + if (enable) { + if (!enable_requested) + I915_WRITE(HSW_PWR_WELL_DRIVER, HSW_PWR_WELL_ENABLE); + + if (!is_enabled) { + DRM_DEBUG_KMS("Enabling power well\n"); + if (wait_for((I915_READ(HSW_PWR_WELL_DRIVER) & + HSW_PWR_WELL_STATE), 20)) + DRM_ERROR("Timeout enabling power well\n"); + } + } else { + if (enable_requested) { + I915_WRITE(HSW_PWR_WELL_DRIVER, 0); + DRM_DEBUG_KMS("Requesting to disable the power well\n"); } } +} + +/* + * Starting with Haswell, we have a "Power Down Well" that can be turned off + * when not needed anymore. We have 4 registers that can request the power well + * to be enabled, and it will only be disabled if none of the registers is + * requesting it to be enabled. + */ +void intel_init_power_well(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; - DRM_UNLOCK(dev); + if (!IS_HASWELL(dev)) + return; + + /* For now, we need the power well to be always enabled. */ + intel_set_power_well(dev, true); + + /* We're taking over the BIOS, so clear any requests made by it since + * the driver is in charge now. */ + if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE) + I915_WRITE(HSW_PWR_WELL_BIOS, 0); } /* Set up chip specific power management-related functions */ @@ -4314,10 +4386,8 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) udelay(10); fifo = I915_READ_NOTRACE(GT_FIFO_FREE_ENTRIES); } - if (loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES) { - kprintf("%s loop\n", __func__); + if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES)) ++ret; - } dev_priv->gt_fifo_count = fifo; } dev_priv->gt_fifo_count--; @@ -4392,6 +4462,7 @@ void intel_gt_init(struct drm_device *dev) int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) { + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) { DRM_DEBUG_DRIVER("warning: pcode (read) mailbox access failed\n"); @@ -4415,6 +4486,7 @@ int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val) int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val) { + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); if (I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) { DRM_DEBUG_DRIVER("warning: pcode (write) mailbox access failed\n"); diff --git a/sys/dev/drm/i915/intel_ringbuffer.c b/sys/dev/drm/i915/intel_ringbuffer.c index d0ecc1de9a..a2f1f4aee4 100644 --- a/sys/dev/drm/i915/intel_ringbuffer.c +++ b/sys/dev/drm/i915/intel_ringbuffer.c @@ -28,10 +28,10 @@ */ #include -#include #include "i915_drv.h" +#include +#include "i915_trace.h" #include "intel_drv.h" -#include "intel_ringbuffer.h" /* * 965+ support PIPE_CONTROL commands, which provide finer grained control @@ -318,6 +318,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, * TLB invalidate requires a post-sync write. */ flags |= PIPE_CONTROL_QW_WRITE; + flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache @@ -331,7 +332,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring, intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4)); intel_ring_emit(ring, flags); - intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); + intel_ring_emit(ring, scratch_addr); intel_ring_emit(ring, 0); intel_ring_advance(ring); @@ -466,9 +467,12 @@ init_pipe_control(struct intel_ring_buffer *ring) pc->cpu_page = (uint32_t *)kmem_alloc_nofault(&kernel_map, PAGE_SIZE, PAGE_SIZE); if (pc->cpu_page == NULL) goto err_unpin; + pmap_qenter((uintptr_t)pc->cpu_page, &obj->pages[0], 1); pmap_invalidate_cache_range((vm_offset_t)pc->cpu_page, (vm_offset_t)pc->cpu_page + PAGE_SIZE); + DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n", + ring->name, pc->gtt_offset); pc->obj = obj; ring->private = pc; @@ -493,6 +497,7 @@ cleanup_pipe_control(struct intel_ring_buffer *ring) return; obj = pc->obj; + pmap_qremove((vm_offset_t)pc->cpu_page, 1); kmem_free(&kernel_map, (uintptr_t)pc->cpu_page, PAGE_SIZE); i915_gem_object_unpin(obj); @@ -616,6 +621,13 @@ gen6_add_request(struct intel_ring_buffer *ring) return 0; } +static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev, + u32 seqno) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + return dev_priv->last_seqno < seqno; +} + /** * intel_ring_sync - sync the waiter to the signaller on seqno * @@ -646,11 +658,20 @@ gen6_ring_sync(struct intel_ring_buffer *waiter, if (ret) return ret; - intel_ring_emit(waiter, - dw1 | signaller->semaphore_register[waiter->id]); - intel_ring_emit(waiter, seqno); - intel_ring_emit(waiter, 0); - intel_ring_emit(waiter, MI_NOOP); + /* If seqno wrap happened, omit the wait with no-ops */ + if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) { + intel_ring_emit(waiter, + dw1 | + signaller->semaphore_register[waiter->id]); + intel_ring_emit(waiter, seqno); + intel_ring_emit(waiter, 0); + intel_ring_emit(waiter, MI_NOOP); + } else { + intel_ring_emit(waiter, MI_NOOP); + intel_ring_emit(waiter, MI_NOOP); + intel_ring_emit(waiter, MI_NOOP); + intel_ring_emit(waiter, MI_NOOP); + } intel_ring_advance(waiter); return 0; @@ -731,6 +752,12 @@ ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency) return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } +static void +ring_set_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno); +} + static u32 pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency) { @@ -738,6 +765,13 @@ pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency) return pc->cpu_page[0]; } +static void +pc_render_set_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + struct pipe_control *pc = ring->private; + pc->cpu_page[0] = seqno; +} + static bool gen5_ring_get_irq(struct intel_ring_buffer *ring) { @@ -1096,8 +1130,7 @@ static int init_status_page(struct intel_ring_buffer *ring) ret = -ENOMEM; goto err_unpin; } - pmap_qenter((vm_offset_t)ring->status_page.page_addr, &obj->pages[0], - 1); + pmap_qenter((vm_offset_t)ring->status_page.page_addr, &obj->pages[0], 1); pmap_invalidate_cache_range((vm_offset_t)ring->status_page.page_addr, (vm_offset_t)ring->status_page.page_addr + PAGE_SIZE); ring->status_page.obj = obj; @@ -1165,7 +1198,11 @@ static int intel_init_ring_buffer(struct drm_device *dev, return ret; } - obj = i915_gem_alloc_object(dev, ring->size); + obj = NULL; + if (!HAS_LLC(dev)) + obj = i915_gem_alloc_object(dev, ring->size); + if (obj == NULL) + obj = i915_gem_alloc_object(dev, ring->size); if (obj == NULL) { DRM_ERROR("Failed to allocate ringbuffer\n"); ret = -ENOMEM; @@ -1182,8 +1219,9 @@ static int intel_init_ring_buffer(struct drm_device *dev, if (ret) goto err_unpin; - ring->virtual_start = ioremap_wc(dev->agp->base + obj->gtt_offset, - ring->size); + ring->virtual_start = + ioremap_wc(dev->agp->base + obj->gtt_offset, + ring->size); if (ring->virtual_start == NULL) { DRM_ERROR("Failed to map ringbuffer.\n"); ret = -EINVAL; @@ -1324,6 +1362,7 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) if (ret != -ENOSPC) return ret; + trace_i915_ring_wait_begin(ring); /* With GEM the hangcheck timer should kick us out of the loop, * leaving it early runs the risk of corrupting GEM state (due * to running on almost untested codepaths). But on resume @@ -1335,6 +1374,7 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) ring->head = I915_READ_HEAD(ring); ring->space = ring_space(ring); if (ring->space >= n) { + trace_i915_ring_wait_end(ring); return 0; } @@ -1351,10 +1391,12 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n) msleep(1); - ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); if (ret) return ret; } while (!time_after(jiffies, end)); + trace_i915_ring_wait_end(ring); return -EBUSY; } @@ -1412,14 +1454,35 @@ intel_ring_alloc_seqno(struct intel_ring_buffer *ring) return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_request); } +static int __intel_ring_begin(struct intel_ring_buffer *ring, + int bytes) +{ + int ret; + + if (unlikely(ring->tail + bytes > ring->effective_size)) { + ret = intel_wrap_ring_buffer(ring); + if (unlikely(ret)) + return ret; + } + + if (unlikely(ring->space < bytes)) { + ret = ring_wait_for_space(ring, bytes); + if (unlikely(ret)) + return ret; + } + + ring->space -= bytes; + return 0; +} + int intel_ring_begin(struct intel_ring_buffer *ring, int num_dwords) { drm_i915_private_t *dev_priv = ring->dev->dev_private; - int n = 4*num_dwords; int ret; - ret = i915_gem_check_wedge(dev_priv, dev_priv->mm.interruptible); + ret = i915_gem_check_wedge(&dev_priv->gpu_error, + dev_priv->mm.interruptible); if (ret) return ret; @@ -1428,20 +1491,21 @@ int intel_ring_begin(struct intel_ring_buffer *ring, if (ret) return ret; - if (unlikely(ring->tail + n > ring->effective_size)) { - ret = intel_wrap_ring_buffer(ring); - if (unlikely(ret)) - return ret; - } + return __intel_ring_begin(ring, num_dwords * sizeof(uint32_t)); +} - if (unlikely(ring->space < n)) { - ret = ring_wait_for_space(ring, n); - if (unlikely(ret)) - return ret; +void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + + BUG_ON(ring->outstanding_lazy_request); + + if (INTEL_INFO(ring->dev)->gen >= 6) { + I915_WRITE(RING_SYNC_0(ring->mmio_base), 0); + I915_WRITE(RING_SYNC_1(ring->mmio_base), 0); } - ring->space -= n; - return 0; + ring->set_seqno(ring, seqno); } void intel_ring_advance(struct intel_ring_buffer *ring) @@ -1449,7 +1513,7 @@ void intel_ring_advance(struct intel_ring_buffer *ring) struct drm_i915_private *dev_priv = ring->dev->dev_private; ring->tail &= ring->size - 1; - if (dev_priv->stop_rings & intel_ring_flag(ring)) + if (dev_priv->gpu_error.stop_rings & intel_ring_flag(ring)) return; ring->write_tail(ring, ring->tail); } @@ -1606,6 +1670,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->irq_put = gen6_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT; ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; ring->sync_to = gen6_ring_sync; ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID; ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV; @@ -1616,6 +1681,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) ring->add_request = pc_render_add_request; ring->flush = gen4_render_ring_flush; ring->get_seqno = pc_render_get_seqno; + ring->set_seqno = pc_render_set_seqno; ring->irq_get = gen5_ring_get_irq; ring->irq_put = gen5_ring_put_irq; ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY; @@ -1626,6 +1692,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev) else ring->flush = gen4_render_ring_flush; ring->get_seqno = ring_get_seqno; + ring->set_seqno = ring_set_seqno; if (IS_GEN2(dev)) { ring->irq_get = i8xx_ring_get_irq; ring->irq_put = i8xx_ring_put_irq; @@ -1697,6 +1764,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) else ring->flush = gen4_render_ring_flush; ring->get_seqno = ring_get_seqno; + ring->set_seqno = ring_set_seqno; if (IS_GEN2(dev)) { ring->irq_get = i8xx_ring_get_irq; ring->irq_put = i8xx_ring_put_irq; @@ -1757,6 +1825,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->flush = gen6_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; @@ -1772,6 +1841,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev) ring->flush = bsd_ring_flush; ring->add_request = i9xx_add_request; ring->get_seqno = ring_get_seqno; + ring->set_seqno = ring_set_seqno; if (IS_GEN5(dev)) { ring->irq_enable_mask = GT_BSD_USER_INTERRUPT; ring->irq_get = gen5_ring_get_irq; @@ -1801,6 +1871,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev) ring->flush = blt_ring_flush; ring->add_request = gen6_add_request; ring->get_seqno = gen6_ring_get_seqno; + ring->set_seqno = ring_set_seqno; ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT; ring->irq_get = gen6_ring_get_irq; ring->irq_put = gen6_ring_put_irq; @@ -1828,6 +1899,8 @@ intel_ring_flush_all_caches(struct intel_ring_buffer *ring) if (ret) return ret; + trace_i915_gem_ring_flush(ring, 0, I915_GEM_GPU_DOMAINS); + ring->gpu_caches_dirty = false; return 0; } @@ -1846,6 +1919,8 @@ intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring) if (ret) return ret; + trace_i915_gem_ring_flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + ring->gpu_caches_dirty = false; return 0; } diff --git a/sys/dev/drm/i915/intel_ringbuffer.h b/sys/dev/drm/i915/intel_ringbuffer.h index 2c6e90e5dc..3d0b3a2cde 100644 --- a/sys/dev/drm/i915/intel_ringbuffer.h +++ b/sys/dev/drm/i915/intel_ringbuffer.h @@ -90,6 +90,8 @@ struct intel_ring_buffer { */ u32 (*get_seqno)(struct intel_ring_buffer *ring, bool lazy_coherency); + void (*set_seqno)(struct intel_ring_buffer *ring, + u32 seqno); int (*dispatch_execbuffer)(struct intel_ring_buffer *ring, u32 offset, u32 length, unsigned flags); @@ -178,6 +180,13 @@ intel_read_status_page(struct intel_ring_buffer *ring, return ring->status_page.page_addr[reg]; } +static inline void +intel_write_status_page(struct intel_ring_buffer *ring, + int reg, u32 value) +{ + ring->status_page.page_addr[reg] = value; +} + /** * Reads a dword out of the status page, which is written to from the command * queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or @@ -208,7 +217,7 @@ static inline void intel_ring_emit(struct intel_ring_buffer *ring, } void intel_ring_advance(struct intel_ring_buffer *ring); int __must_check intel_ring_idle(struct intel_ring_buffer *ring); - +void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno); int intel_ring_flush_all_caches(struct intel_ring_buffer *ring); int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring); diff --git a/sys/dev/drm/i915/intel_sdvo.c b/sys/dev/drm/i915/intel_sdvo.c index d82aee8ee2..e632385a7a 100644 --- a/sys/dev/drm/i915/intel_sdvo.c +++ b/sys/dev/drm/i915/intel_sdvo.c @@ -97,13 +97,14 @@ struct intel_sdvo { /* * Hotplug activation bits for this device */ - uint8_t hotplug_active[2]; + uint16_t hotplug_active; /** * This is used to select the color range of RBG outputs in HDMI mode. * It is only valid when using TMDS encoding and 8 bit per color mode. */ uint32_t color_range; + bool color_range_auto; /** * This is set if we're going to treat the device as TV-out. @@ -126,6 +127,7 @@ struct intel_sdvo { bool is_hdmi; bool has_hdmi_monitor; bool has_hdmi_audio; + bool rgb_quant_range_selectable; /** * This is set if we detect output of sdvo device as LVDS and @@ -420,16 +422,16 @@ static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, for (i = 0; i < args_len; i++) kprintf("%02X ", ((const u8 *)args)[i]); for (; i < 8; i++) - kprintf(" "); + DRM_LOG_KMS(" "); for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - kprintf("(%s)", sdvo_cmd_names[i].name); + DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); break; } } if (i == ARRAY_SIZE(sdvo_cmd_names)) - kprintf("(%02X)", cmd); - kprintf("\n"); + DRM_LOG_KMS("(%02X)", cmd); + DRM_LOG_KMS("\n"); } static const char *cmd_status_names[] = { @@ -538,9 +540,9 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, } if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - DRM_DEBUG_KMS("(%s)", cmd_status_names[status]); + DRM_LOG_KMS("(%s)", cmd_status_names[status]); else - DRM_DEBUG_KMS("(??? %d)", status); + DRM_LOG_KMS("(??? %d)", status); if (status != SDVO_CMD_STATUS_SUCCESS) goto log_fail; @@ -551,13 +553,13 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - DRM_DEBUG_KMS(" %02X", ((u8 *)response)[i]); + DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); } - DRM_DEBUG_KMS("\n"); + DRM_LOG_KMS("\n"); return true; log_fail: - DRM_DEBUG_KMS("... failed\n"); + DRM_LOG_KMS("... failed\n"); return false; } @@ -615,7 +617,7 @@ static bool intel_sdvo_get_trained_inputs(struct intel_sdvo *intel_sdvo, bool *i { struct intel_sdvo_get_trained_inputs_response response; - CTASSERT(sizeof(response) == 1); + BUILD_BUG_ON(sizeof(response) != 1); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_TRAINED_INPUTS, &response, sizeof(response))) return false; @@ -671,7 +673,7 @@ static bool intel_sdvo_get_input_pixel_clock_range(struct intel_sdvo *intel_sdvo { struct intel_sdvo_pixel_clock_range clocks; - CTASSERT(sizeof(clocks) == 4); + BUILD_BUG_ON(sizeof(clocks) != 4); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE, &clocks, sizeof(clocks))) @@ -739,8 +741,8 @@ intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo, static bool intel_sdvo_get_preferred_input_timing(struct intel_sdvo *intel_sdvo, struct intel_sdvo_dtd *dtd) { - CTASSERT(sizeof(dtd->part1) == 8); - CTASSERT(sizeof(dtd->part2) == 8); + BUILD_BUG_ON(sizeof(dtd->part1) != 8); + BUILD_BUG_ON(sizeof(dtd->part2) != 8); return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1, &dtd->part1, sizeof(dtd->part1)) && intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2, @@ -835,9 +837,11 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->clock = dtd->part1.clock * 10; mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); - if (dtd->part2.dtd_flags & 0x2) + if (dtd->part2.dtd_flags & DTD_FLAG_INTERLACE) + mode->flags |= DRM_MODE_FLAG_INTERLACE; + if (dtd->part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE) mode->flags |= DRM_MODE_FLAG_PHSYNC; - if (dtd->part2.dtd_flags & 0x4) + if (dtd->part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE) mode->flags |= DRM_MODE_FLAG_PVSYNC; } @@ -845,7 +849,7 @@ static bool intel_sdvo_check_supp_encode(struct intel_sdvo *intel_sdvo) { struct intel_sdvo_encode encode; - CTASSERT(sizeof(encode) == 2); + BUILD_BUG_ON(sizeof(encode) != 2); return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_SUPP_ENCODE, &encode, sizeof(encode)); @@ -932,7 +936,8 @@ static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, &tx_rate, 1); } -static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) +static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo, + const struct drm_display_mode *adjusted_mode) { struct dip_infoframe avi_if = { .type = DIP_TYPE_AVI, @@ -941,6 +946,13 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo) }; uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)]; + if (intel_sdvo->rgb_quant_range_selectable) { + if (adjusted_mode->private_flags & INTEL_MODE_LIMITED_COLOR_RANGE) + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_LIMITED; + else + avi_if.body.avi.ITC_EC_Q_SC |= DIP_AVI_RGB_QUANT_RANGE_FULL; + } + intel_dip_infoframe_csum(&avi_if); /* sdvo spec says that the ecc is handled by the hw, and it looks like @@ -963,7 +975,7 @@ static bool intel_sdvo_set_tv_format(struct intel_sdvo *intel_sdvo) memset(&format, 0, sizeof(format)); memcpy(&format, &format_map, min(sizeof(format), sizeof(format_map))); - CTASSERT(sizeof(format) == 6); + BUILD_BUG_ON(sizeof(format) != 6); return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_TV_FORMAT, &format, sizeof(format)); @@ -1050,6 +1062,18 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode); intel_mode_set_pixel_multiplier(adjusted_mode, multiplier); + if (intel_sdvo->color_range_auto) { + /* See CEA-861-E - 5.1 Default Encoding Parameters */ + if (intel_sdvo->has_hdmi_monitor && + drm_match_cea_mode(adjusted_mode) > 1) + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + else + intel_sdvo->color_range = 0; + } + + if (intel_sdvo->color_range) + adjusted_mode->private_flags |= INTEL_MODE_LIMITED_COLOR_RANGE; + return true; } @@ -1107,7 +1131,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI); intel_sdvo_set_colorimetry(intel_sdvo, SDVO_COLORIMETRY_RGB256); - intel_sdvo_set_avi_infoframe(intel_sdvo); + intel_sdvo_set_avi_infoframe(intel_sdvo, adjusted_mode); } else intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_DVI); @@ -1139,7 +1163,7 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* The real mode polarity is set by the SDVO commands, using * struct intel_sdvo_dtd. */ sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; - if (intel_sdvo->is_hdmi) + if (!HAS_PCH_SPLIT(dev) && intel_sdvo->is_hdmi) sdvox |= intel_sdvo->color_range; if (INTEL_INFO(dev)->gen < 5) sdvox |= SDVO_BORDER_ENABLE; @@ -1371,7 +1395,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps) { - CTASSERT(sizeof(*caps) == 8); + BUILD_BUG_ON(sizeof(*caps) != 8); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps))) @@ -1425,14 +1449,14 @@ static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder) struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base); intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG, - &intel_sdvo->hotplug_active, 2); + &intel_sdvo->hotplug_active, 2); } static bool intel_sdvo_multifunc_encoder(struct intel_sdvo *intel_sdvo) { /* Is there more than one type of output? */ - return bitcount16(intel_sdvo->caps.output_flags) > 1; + return hweight16(intel_sdvo->caps.output_flags) > 1; } static struct edid * @@ -1449,7 +1473,8 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector) struct drm_i915_private *dev_priv = connector->dev->dev_private; return drm_get_edid(connector, - intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin)); + intel_gmbus_get_adapter(dev_priv, + dev_priv->crt_ddc_pin)); } static enum drm_connector_status @@ -1497,6 +1522,8 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) if (intel_sdvo->is_hdmi) { intel_sdvo->has_hdmi_monitor = drm_detect_hdmi_monitor(edid); intel_sdvo->has_hdmi_audio = drm_detect_monitor_audio(edid); + intel_sdvo->rgb_quant_range_selectable = + drm_rgb_quant_range_selectable(edid); } } else status = connector_status_disconnected; @@ -1548,6 +1575,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) intel_sdvo->has_hdmi_monitor = false; intel_sdvo->has_hdmi_audio = false; + intel_sdvo->rgb_quant_range_selectable = false; if ((intel_sdvo_connector->output_flag & response) == 0) ret = connector_status_disconnected; @@ -1698,7 +1726,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) if (!intel_sdvo_set_target_output(intel_sdvo, intel_sdvo->attached_output)) return; - CTASSERT(sizeof(tv_res) == 3); + BUILD_BUG_ON(sizeof(tv_res) != 3); if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, &tv_res, sizeof(tv_res))) @@ -1727,11 +1755,14 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) * Assume that the preferred modes are * arranged in priority order. */ - intel_ddc_get_modes(connector, intel_sdvo->i2c); - if (!list_empty(&connector->probed_modes)) - goto end; + intel_ddc_get_modes(connector, intel_sdvo->ddc); - /* Fetch modes from VBT */ + /* + * Fetch modes from VBT. For SDVO prefer the VBT mode since some + * SDVO->LVDS transcoders can't cope with the EDID mode. Since + * drm_mode_probed_add adds the mode at the head of the list we add it + * last. + */ if (dev_priv->sdvo_lvds_vbt_mode != NULL) { newmode = drm_mode_duplicate(connector->dev, dev_priv->sdvo_lvds_vbt_mode); @@ -1743,7 +1774,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) } } -end: list_for_each_entry(newmode, &connector->probed_modes, head) { if (newmode->type & DRM_MODE_TYPE_PREFERRED) { intel_sdvo->sdvo_lvds_fixed_mode = @@ -1882,10 +1912,21 @@ intel_sdvo_set_property(struct drm_connector *connector, } if (property == dev_priv->broadcast_rgb_property) { - if (val == !!intel_sdvo->color_range) - return 0; - - intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0; + switch (val) { + case INTEL_BROADCAST_RGB_AUTO: + intel_sdvo->color_range_auto = true; + break; + case INTEL_BROADCAST_RGB_FULL: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = 0; + break; + case INTEL_BROADCAST_RGB_LIMITED: + intel_sdvo->color_range_auto = false; + intel_sdvo->color_range = SDVO_COLOR_RANGE_16_235; + break; + default: + return -EINVAL; + } goto done; } @@ -1982,11 +2023,8 @@ set_value: done: - if (intel_sdvo->base.base.crtc) { - struct drm_crtc *crtc = intel_sdvo->base.base.crtc; - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); - } + if (intel_sdvo->base.base.crtc) + intel_crtc_restore_mode(intel_sdvo->base.base.crtc); return 0; #undef CHECK_PROPERTY @@ -2056,7 +2094,7 @@ intel_sdvo_guess_ddc_bus(struct intel_sdvo *sdvo) /* Count bits to find what number we are in the priority list. */ mask &= sdvo->caps.output_flags; - num_bits = bitcount16(mask); + num_bits = hweight16(mask); /* If more than 3 outputs, default to DDC bus 3 for now. */ if (num_bits > 3) num_bits = 3; @@ -2106,7 +2144,7 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, else pin = GMBUS_PORT_DPB; - sdvo->i2c = dev_priv->gmbus[pin]; + sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin); /* With gmbus we should be able to drive sdvo i2c at 2MHz, but somehow * our code totally fails once we start using gmbus. Hence fall back to @@ -2188,13 +2226,16 @@ intel_sdvo_connector_init(struct intel_sdvo_connector *connector, } static void -intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector) +intel_sdvo_add_hdmi_properties(struct intel_sdvo *intel_sdvo, + struct intel_sdvo_connector *connector) { struct drm_device *dev = connector->base.base.dev; intel_attach_force_audio_property(&connector->base.base); - if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) + if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev)) { intel_attach_broadcast_rgb_property(&connector->base.base); + intel_sdvo->color_range_auto = true; + } } static bool @@ -2208,6 +2249,8 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector = kmalloc(sizeof(struct intel_sdvo_connector), M_DRM, M_WAITOK | M_ZERO); + if (!intel_sdvo_connector) + return false; if (device == 0) { intel_sdvo->controlled_output |= SDVO_OUTPUT_TMDS0; @@ -2221,7 +2264,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) connector = &intel_connector->base; if (intel_sdvo_supports_hotplug(intel_sdvo) & (1 << device)) { connector->polled = DRM_CONNECTOR_POLL_HPD; - intel_sdvo->hotplug_active[0] |= 1 << device; + intel_sdvo->hotplug_active |= intel_sdvo_connector->output_flag; /* Some SDVO devices have one-shot hotplug interrupts. * Ensure that they get re-enabled when an interrupt happens. */ @@ -2240,7 +2283,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (intel_sdvo->is_hdmi) - intel_sdvo_add_hdmi_properties(intel_sdvo_connector); + intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector); return true; } @@ -2294,6 +2337,8 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector = kmalloc(sizeof(struct intel_sdvo_connector), M_DRM, M_WAITOK | M_ZERO); + if (!intel_sdvo_connector) + return false; intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; @@ -2324,6 +2369,8 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector = kmalloc(sizeof(struct intel_sdvo_connector), M_DRM, M_WAITOK | M_ZERO); + if (!intel_sdvo_connector) + return false; intel_connector = &intel_sdvo_connector->base; connector = &intel_connector->base; @@ -2433,7 +2480,7 @@ static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo, if (!intel_sdvo_set_target_output(intel_sdvo, type)) return false; - CTASSERT(sizeof(format) == 6); + BUILD_BUG_ON(sizeof(format) != 6); if (!intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_SUPPORTED_TV_FORMATS, &format, sizeof(format))) @@ -2626,7 +2673,7 @@ static bool intel_sdvo_create_enhance_property(struct intel_sdvo *intel_sdvo, uint16_t response; } enhancements; - CTASSERT(sizeof(enhancements) == 2); + BUILD_BUG_ON(sizeof(enhancements) != 2); enhancements.response = 0; intel_sdvo_get_value(intel_sdvo, diff --git a/sys/dev/drm/i915/intel_sprite.c b/sys/dev/drm/i915/intel_sprite.c index 2a2670f835..95baf510e8 100644 --- a/sys/dev/drm/i915/intel_sprite.c +++ b/sys/dev/drm/i915/intel_sprite.c @@ -50,6 +50,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); + bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; sprctl = I915_READ(SPRCTL(pipe)); @@ -89,6 +90,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, sprctl |= SPRITE_TRICKLE_FEED_DISABLE; sprctl |= SPRITE_ENABLE; + if (IS_HASWELL(dev)) + sprctl |= SPRITE_PIPE_CSC_ENABLE; + /* Sizes are 0 based */ src_w--; src_h--; @@ -103,19 +107,15 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, * when scaling is disabled. */ if (crtc_w != src_w || crtc_h != src_h) { - if (!dev_priv->sprite_scaling_enabled) { - dev_priv->sprite_scaling_enabled = true; + dev_priv->sprite_scaling_enabled |= 1 << pipe; + + if (!scaling_was_enabled) { intel_update_watermarks(dev); intel_wait_for_vblank(dev, pipe); } sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h; - } else { - if (dev_priv->sprite_scaling_enabled) { - dev_priv->sprite_scaling_enabled = false; - /* potentially re-enable LP watermarks */ - intel_update_watermarks(dev); - } - } + } else + dev_priv->sprite_scaling_enabled &= ~(1 << pipe); I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); @@ -141,6 +141,10 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb, I915_WRITE(SPRCTL(pipe), sprctl); I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); + + /* potentially re-enable LP watermarks */ + if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) + intel_update_watermarks(dev); } static void @@ -150,6 +154,7 @@ ivb_disable_plane(struct drm_plane *plane) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_plane *intel_plane = to_intel_plane(plane); int pipe = intel_plane->pipe; + bool scaling_was_enabled = dev_priv->sprite_scaling_enabled; I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); /* Can't leave the scaler enabled... */ @@ -159,8 +164,11 @@ ivb_disable_plane(struct drm_plane *plane) I915_MODIFY_DISPBASE(SPRSURF(pipe), 0); POSTING_READ(SPRSURF(pipe)); - dev_priv->sprite_scaling_enabled = false; - intel_update_watermarks(dev); + dev_priv->sprite_scaling_enabled &= ~(1 << pipe); + + /* potentially re-enable LP watermarks */ + if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled) + intel_update_watermarks(dev); } static int @@ -503,7 +511,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, (crtc_w == primary_w) && (crtc_h == primary_h)) disable_primary = true; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj, NULL); if (ret) @@ -533,15 +541,15 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, * do the pin & ref bookkeeping. */ if (old_obj != obj) { - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); } intel_unpin_fb_obj(old_obj); } out_unlock: - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); out: return ret; } @@ -560,10 +568,10 @@ intel_disable_plane(struct drm_plane *plane) if (!intel_plane->obj) goto out; - DRM_LOCK(dev); + mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(intel_plane->obj); intel_plane->obj = NULL; - DRM_UNLOCK(dev); + mutex_unlock(&dev->struct_mutex); out: return ret; @@ -593,7 +601,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) return -EINVAL; - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE); if (!obj) { @@ -606,7 +614,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, ret = intel_plane->update_colorkey(plane, set); out_unlock: - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + drm_modeset_unlock_all(dev); return ret; } @@ -622,7 +630,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -ENODEV; - lockmgr(&dev->mode_config.mutex, LK_EXCLUSIVE); + drm_modeset_lock_all(dev); obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE); if (!obj) { @@ -635,7 +643,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data, intel_plane->get_colorkey(plane, get); out_unlock: - lockmgr(&dev->mode_config.mutex, LK_RELEASE); + drm_modeset_unlock_all(dev); return ret; } diff --git a/sys/dev/drm/i915/intel_tv.c b/sys/dev/drm/i915/intel_tv.c index 8d0a6c72d5..b7ee87a789 100644 --- a/sys/dev/drm/i915/intel_tv.c +++ b/sys/dev/drm/i915/intel_tv.c @@ -1411,7 +1411,7 @@ intel_tv_get_modes(struct drm_connector *connector) tmp = (u64) tv_mode->refresh * mode_ptr->vtotal; tmp *= mode_ptr->htotal; - tmp = tmp / 1000000; + tmp = div_u64(tmp, 1000000); mode_ptr->clock = (int) tmp; mode_ptr->type = DRM_MODE_TYPE_DRIVER; @@ -1430,7 +1430,7 @@ intel_tv_destroy(struct drm_connector *connector) drm_sysfs_connector_remove(connector); #endif drm_connector_cleanup(connector); - drm_free(connector, M_DRM); + kfree(connector, M_DRM); } @@ -1480,8 +1480,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop } if (changed && crtc) - intel_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + intel_crtc_restore_mode(crtc); out: return ret; } @@ -1489,7 +1488,6 @@ out: static const struct drm_encoder_helper_funcs intel_tv_helper_funcs = { .mode_fixup = intel_tv_mode_fixup, .mode_set = intel_tv_mode_set, - .disable = intel_encoder_noop, }; static const struct drm_connector_funcs intel_tv_connector_funcs = { @@ -1592,8 +1590,7 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_tv = kmalloc(sizeof(struct intel_tv), M_DRM, - M_WAITOK | M_ZERO); + intel_tv = kmalloc(sizeof(struct intel_tv), M_DRM, M_WAITOK | M_ZERO); if (!intel_tv) { return; } diff --git a/sys/dev/drm/include/drm/drmP.h b/sys/dev/drm/include/drm/drmP.h index a2b5fc30f4..45553fadc3 100644 --- a/sys/dev/drm/include/drm/drmP.h +++ b/sys/dev/drm/include/drm/drmP.h @@ -90,10 +90,13 @@ #include #include +MALLOC_DECLARE(M_DRM); + #include #include #include +#include #include #include #include @@ -104,10 +107,12 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -174,8 +179,6 @@ struct drm_device; #define DRM_GEM_MAPPING_MAPOFF(o) \ ((o) & ~(DRM_GEM_MAPPING_OFF(DRM_GEM_MAX_IDX) | DRM_GEM_MAPPING_KEY)) -MALLOC_DECLARE(M_DRM); - SYSCTL_DECL(_hw_drm); #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -203,13 +206,13 @@ SYSCTL_DECL(_hw_drm); #define DRM_CURPROC curthread #define DRM_STRUCTPROC struct thread #define DRM_CURRENTPID (curproc != NULL ? curproc->p_pid : -1) -#define DRM_LOCK(dev) lockmgr(&(dev)->dev_struct_lock, LK_EXCLUSIVE) -#define DRM_UNLOCK(dev) lockmgr(&(dev)->dev_struct_lock, LK_RELEASE) +#define DRM_LOCK(dev) lockmgr(&(dev)->struct_mutex, LK_EXCLUSIVE) +#define DRM_UNLOCK(dev) lockmgr(&(dev)->struct_mutex, LK_RELEASE) #define DRM_LOCK_SLEEP(dev, chan, flags, msg, timeout) \ - (lksleep((chan), &(dev)->dev_struct_lock, (flags), (msg), (timeout))) + (lksleep((chan), &(dev)->struct_mutex, (flags), (msg), (timeout))) #if defined(INVARIANTS) -#define DRM_LOCK_ASSERT(dev) KKASSERT(lockstatus(&(dev)->dev_struct_lock, curthread) != 0); -#define DRM_UNLOCK_ASSERT(dev) KKASSERT(lockstatus(&(dev)->dev_struct_lock, curthread) == 0); +#define DRM_LOCK_ASSERT(dev) KKASSERT(lockstatus(&(dev)->struct_mutex, curthread) != 0); +#define DRM_UNLOCK_ASSERT(dev) KKASSERT(lockstatus(&(dev)->struct_mutex, curthread) == 0); #else #define DRM_LOCK_ASSERT(d) #define DRM_UNLOCK_ASSERT(d) @@ -328,6 +331,11 @@ vm_page_t vm_phys_fictitious_to_vm_page(vm_paddr_t pa); __func__ , ##__VA_ARGS__); \ } while (0) +#define DRM_LOG_KMS(fmt, ...) do { \ + kprintf("[" DRM_NAME ":KMS:pid%d:%s] " fmt, DRM_CURRENTPID, \ + __func__ , ##__VA_ARGS__); \ +} while (0) + #define dev_dbg(dev, fmt, ...) do { \ if ((drm_debug& DRM_DEBUGBITS_KMS) != 0) { \ device_printf((dev), "debug: " fmt, ## __VA_ARGS__); \ @@ -883,7 +891,6 @@ struct drm_device { struct spinlock dma_lock; /* protects dev->dma */ struct lwkt_serialize irq_lock; /* protects irq condition checks */ struct lock dev_lock; /* protects everything else */ - struct lock dev_struct_lock; /** \name Locks */ /*@{ */ diff --git a/sys/dev/drm/include/drm/drm_crtc.h b/sys/dev/drm/include/drm/drm_crtc.h index 3eae073f12..19083362c7 100644 --- a/sys/dev/drm/include/drm/drm_crtc.h +++ b/sys/dev/drm/include/drm/drm_crtc.h @@ -36,7 +36,8 @@ struct drm_device; struct drm_mode_set; struct drm_framebuffer; struct drm_object_properties; - +struct drm_file; +struct drm_clip_rect; #define DRM_MODE_OBJECT_CRTC 0xcccccccc #define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 @@ -117,7 +118,7 @@ enum drm_mode_status { .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ - .vscan = (vs), .flags = (f), .vrefresh = 0, \ + .vscan = (vs), .flags = (f), \ .base.type = DRM_MODE_OBJECT_MODE #define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ @@ -252,6 +253,10 @@ struct drm_framebuffer { * userspace perspective. */ struct kref refcount; + /* + * Place on the dev->mode_config.fb_list, access protected by + * dev->mode_config.fb_lock. + */ struct list_head head; struct drm_mode_object base; const struct drm_framebuffer_funcs *funcs; @@ -303,7 +308,7 @@ struct drm_plane; * drm_crtc_funcs - control CRTCs for a given device * @save: save CRTC state * @restore: restore CRTC state - * @reset: reset CRTC after state has been invalidate (e.g. resume) + * @reset: reset CRTC after state has been invalidated (e.g. resume) * @cursor_set: setup the cursor * @cursor_move: move the cursor * @gamma_set: specify color ramp for CRTC @@ -388,6 +393,15 @@ struct drm_crtc { struct drm_device *dev; struct list_head head; + /** + * crtc mutex + * + * This provides a read lock for the overall crtc state (mode, dpms + * state, ...) and a write lock for everything which can be update + * without a full modeset (fb, cursor data, ...) + */ + struct lock mutex; + struct drm_mode_object base; /* framebuffer the connector is currently bound to */ @@ -427,12 +441,12 @@ struct drm_crtc { * @dpms: set power state (see drm_crtc_funcs above) * @save: save connector state * @restore: restore connector state - * @reset: reset connector after state has been invalidate (e.g. resume) + * @reset: reset connector after state has been invalidated (e.g. resume) * @detect: is this connector active? * @fill_modes: fill mode list for this connector - * @set_property: property for this connector may need update + * @set_property: property for this connector may need an update * @destroy: make object go away - * @force: notify the driver the connector is forced on + * @force: notify the driver that the connector is forced on * * Each CRTC may have one or more connectors attached to it. The functions * below allow the core DRM code to control connectors, enumerate available modes, @@ -538,7 +552,6 @@ enum drm_connector_force { * @probed_modes: list of modes derived directly from the display * @display_info: information about attached display (e.g. from EDID) * @funcs: connector control functions - * @user_modes: user added mode list * @edid_blob_ptr: DRM property containing EDID if present * @properties: property tracking for this connector * @polled: a %DRM_CONNECTOR_POLL_ value for core driven polling @@ -582,7 +595,6 @@ struct drm_connector { struct drm_display_info display_info; const struct drm_connector_funcs *funcs; - struct list_head user_modes; struct drm_property_blob *edid_blob_ptr; struct drm_object_properties properties; @@ -769,8 +781,18 @@ struct drm_mode_config { struct lock idr_mutex; /* for IDR management */ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ /* this is limited to one for now */ + + + /** + * fb_lock - mutex to protect fb state + * + * Besides the global fb list his also protects the fbs list in the + * file_priv + */ + struct lock fb_lock; int num_fb; struct list_head fb_list; + int num_connector; struct list_head connector_list; int num_encoder; @@ -840,6 +862,10 @@ struct drm_prop_enum_list { char *name; }; +extern void drm_modeset_lock_all(struct drm_device *dev); +extern void drm_modeset_unlock_all(struct drm_device *dev); +extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); + extern int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, const struct drm_crtc_funcs *funcs); @@ -892,15 +918,11 @@ extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); +extern bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); extern int drm_mode_width(const struct drm_display_mode *mode); extern int drm_mode_height(const struct drm_display_mode *mode); /* for us by fb module */ -extern int drm_mode_attachmode_crtc(struct drm_device *dev, - struct drm_crtc *crtc, - const struct drm_display_mode *mode); -extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode); - extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); extern void drm_mode_list_concat(struct list_head *head, @@ -908,6 +930,9 @@ extern void drm_mode_list_concat(struct list_head *head, extern void drm_mode_validate_size(struct drm_device *dev, struct list_head *mode_list, int maxX, int maxY, int maxPitch); +extern void drm_mode_validate_clocks(struct drm_device *dev, + struct list_head *mode_list, + int *min, int *max, int n_ranges); extern void drm_mode_prune_invalid(struct drm_device *dev, struct list_head *mode_list, bool verbose); extern void drm_mode_sort(struct list_head *mode_list); @@ -930,10 +955,13 @@ extern void drm_framebuffer_set_object(struct drm_device *dev, extern int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs); +extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, + uint32_t id); extern void drm_framebuffer_unreference(struct drm_framebuffer *fb); extern void drm_framebuffer_reference(struct drm_framebuffer *fb); extern void drm_framebuffer_remove(struct drm_framebuffer *fb); extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); +extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); @@ -983,6 +1011,7 @@ extern int drm_mode_getcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getconnector(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_mode_set_config_internal(struct drm_mode_set *set); extern int drm_mode_setcrtc(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_getplane(struct drm_device *dev, @@ -1002,14 +1031,6 @@ extern int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_mode_dirtyfb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int drm_mode_addmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_rmmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_attachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); -extern int drm_mode_detachmode_ioctl(struct drm_device *dev, - void *data, struct drm_file *file_priv); extern int drm_mode_getproperty_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); @@ -1028,9 +1049,10 @@ extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern u8 *drm_find_cea_extension(struct edid *edid); -extern u8 drm_match_cea_mode(struct drm_display_mode *to_match); +extern u8 drm_match_cea_mode(const struct drm_display_mode *to_match); extern bool drm_detect_hdmi_monitor(struct edid *edid); extern bool drm_detect_monitor_audio(struct edid *edid); +extern bool drm_rgb_quant_range_selectable(struct edid *edid); extern int drm_mode_page_flip_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, @@ -1045,7 +1067,6 @@ extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev, int GTF_2C, int GTF_K, int GTF_2J); extern int drm_add_modes_noedid(struct drm_connector *connector, int hdisplay, int vdisplay); -extern uint8_t drm_mode_cea_vic(const struct drm_display_mode *mode); extern int drm_edid_header_is_valid(const u8 *raw_edid); extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid); diff --git a/sys/dev/drm/include/drm/drm_edid.h b/sys/dev/drm/include/drm/drm_edid.h index 0cac551c53..fc481fc170 100644 --- a/sys/dev/drm/include/drm/drm_edid.h +++ b/sys/dev/drm/include/drm/drm_edid.h @@ -244,14 +244,29 @@ struct edid { #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) +/* Short Audio Descriptor */ +struct cea_sad { + u8 format; + u8 channels; /* max number of channels - 1 */ + u8 freq; + u8 byte2; /* meaning depends on format */ +}; + struct drm_encoder; struct drm_connector; struct drm_display_mode; +struct hdmi_avi_infoframe; + void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); +int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads); int drm_av_sync_delay(struct drm_connector *connector, struct drm_display_mode *mode); struct drm_connector *drm_select_eld(struct drm_encoder *encoder, struct drm_display_mode *mode); int drm_load_edid_firmware(struct drm_connector *connector); +int +drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, + const struct drm_display_mode *mode); + #endif /* __DRM_EDID_H__ */ diff --git a/sys/dev/drm/include/drm/drm_global.h b/sys/dev/drm/include/drm/drm_global.h index 9dd87e737e..a06805eaf6 100644 --- a/sys/dev/drm/include/drm/drm_global.h +++ b/sys/dev/drm/include/drm/drm_global.h @@ -27,7 +27,6 @@ /* * Authors: Thomas Hellstrom */ -/* $FreeBSD: head/sys/dev/drm2/drm_global.h 247834 2013-03-05 09:27:21Z kib $ */ #ifndef _DRM_GLOBAL_H_ #define _DRM_GLOBAL_H_ diff --git a/sys/dev/drm/include/uapi_drm/drm.h b/sys/dev/drm/include/uapi_drm/drm.h index 7ac4172994..3aad6ba143 100644 --- a/sys/dev/drm/include/uapi_drm/drm.h +++ b/sys/dev/drm/include/uapi_drm/drm.h @@ -692,8 +692,8 @@ struct drm_prime_handle { #define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut) #define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder) #define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector) -#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) -#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) /* deprecated (never worked) */ +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) /* deprecated (never worked) */ #define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property) #define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property) diff --git a/sys/dev/drm/include/uapi_drm/drm_mode.h b/sys/dev/drm/include/uapi_drm/drm_mode.h index 3d6301b6ec..cc2e00eac2 100644 --- a/sys/dev/drm/include/uapi_drm/drm_mode.h +++ b/sys/dev/drm/include/uapi_drm/drm_mode.h @@ -223,6 +223,8 @@ struct drm_mode_get_connector { __u32 connection; __u32 mm_width, mm_height; /**< HxW in millimeters */ __u32 subpixel; + + __u32 pad; }; #define DRM_MODE_PROP_PENDING (1<<0) @@ -367,13 +369,13 @@ struct drm_mode_mode_cmd { * depending on the value in flags different members are used. * * CURSOR_BO uses - * crtc + * crtc_id * width * height - * handle - if 0 turns the cursor of + * handle - if 0 turns the cursor off * * CURSOR_MOVE uses - * crtc + * crtc_id * x * y */ diff --git a/sys/dev/drm/include/uapi_drm/i915_drm.h b/sys/dev/drm/include/uapi_drm/i915_drm.h index 4dbacdfd9f..4650aff03d 100644 --- a/sys/dev/drm/include/uapi_drm/i915_drm.h +++ b/sys/dev/drm/include/uapi_drm/i915_drm.h @@ -308,6 +308,8 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_RSVD_FOR_FUTURE_USE 22 #define I915_PARAM_HAS_SECURE_BATCHES 23 #define I915_PARAM_HAS_PINNED_BATCHES 24 +#define I915_PARAM_HAS_EXEC_NO_RELOC 25 +#define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 typedef struct drm_i915_getparam { int param; @@ -628,7 +630,11 @@ struct drm_i915_gem_exec_object2 { __u64 offset; #define EXEC_OBJECT_NEEDS_FENCE (1<<0) +#define EXEC_OBJECT_NEEDS_GTT (1<<1) +#define EXEC_OBJECT_WRITE (1<<2) +#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_WRITE<<1) __u64 flags; + __u64 rsvd1; __u64 rsvd2; }; @@ -687,6 +693,20 @@ struct drm_i915_gem_execbuffer2 { */ #define I915_EXEC_IS_PINNED (1<<10) +/** Provide a hint to the kernel that the command stream and auxilliary + * state buffers already holds the correct presumed addresses and so the + * relocation process may be skipped if no buffers need to be moved in + * preparation for the execbuffer. + */ +#define I915_EXEC_NO_RELOC (1<<11) + +/** Use the reloc.handle as an index into the exec object array rather + * than as the per-file handle. + */ +#define I915_EXEC_HANDLE_LUT (1<<12) + +#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_HANDLE_LUT<<1) + #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK -- 2.41.0