diff options
Diffstat (limited to 'drivers/gpu')
30 files changed, 2673 insertions, 1900 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4ff9b6cc973..09e0327fc6c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -326,21 +326,21 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data) struct intel_crtc *crtc; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) { - const char *pipe = crtc->pipe ? "B" : "A"; - const char *plane = crtc->plane ? "B" : "A"; + const char pipe = pipe_name(crtc->pipe); + const char plane = plane_name(crtc->plane); struct intel_unpin_work *work; spin_lock_irqsave(&dev->event_lock, flags); work = crtc->unpin_work; if (work == NULL) { - seq_printf(m, "No flip due on pipe %s (plane %s)\n", + seq_printf(m, "No flip due on pipe %c (plane %c)\n", pipe, plane); } else { if (!work->pending) { - seq_printf(m, "Flip queued on pipe %s (plane %s)\n", + seq_printf(m, "Flip queued on pipe %c (plane %c)\n", pipe, plane); } else { - seq_printf(m, "Flip pending (waiting for vsync) on pipe %s (plane %s)\n", + seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n", pipe, plane); } if (work->enable_stall_check) @@ -458,7 +458,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) 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, i; + int ret, i, pipe; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -471,10 +471,10 @@ static int i915_interrupt_info(struct seq_file *m, void *data) I915_READ(IIR)); seq_printf(m, "Interrupt mask: %08x\n", I915_READ(IMR)); - seq_printf(m, "Pipe A stat: %08x\n", - I915_READ(PIPEASTAT)); - seq_printf(m, "Pipe B stat: %08x\n", - I915_READ(PIPEBSTAT)); + for_each_pipe(pipe) + seq_printf(m, "Pipe %c stat: %08x\n", + pipe_name(pipe), + I915_READ(PIPESTAT(pipe))); } else { seq_printf(m, "North Display Interrupt enable: %08x\n", I915_READ(DEIER)); @@ -544,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; - volatile u32 *hws; + const volatile u32 __iomem *hws; int i; ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; - hws = (volatile u32 *)ring->status_page.page_addr; + hws = (volatile u32 __iomem *)ring->status_page.page_addr; if (hws == NULL) return 0; @@ -615,7 +615,7 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data) if (!ring->obj) { seq_printf(m, "No ringbuffer setup\n"); } else { - u8 *virt = ring->virtual_start; + const u8 __iomem *virt = ring->virtual_start; uint32_t off; for (off = 0; off < ring->size; off += 4) { @@ -805,15 +805,20 @@ static int i915_error_state(struct seq_file *m, void *unused) } } - if (error->ringbuffer) { - struct drm_i915_error_object *obj = error->ringbuffer; - - seq_printf(m, "--- ringbuffer = 0x%08x\n", obj->gtt_offset); - offset = 0; - for (page = 0; page < obj->page_count; page++) { - for (elt = 0; elt < PAGE_SIZE/4; elt++) { - seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); - offset += 4; + for (i = 0; i < ARRAY_SIZE(error->ringbuffer); i++) { + if (error->ringbuffer[i]) { + struct drm_i915_error_object *obj = error->ringbuffer[i]; + seq_printf(m, "%s --- ringbuffer = 0x%08x\n", + dev_priv->ring[i].name, + obj->gtt_offset); + offset = 0; + for (page = 0; page < obj->page_count; page++) { + for (elt = 0; elt < PAGE_SIZE/4; elt++) { + seq_printf(m, "%08x : %08x\n", + offset, + obj->pages[page][elt]); + offset += 4; + } } } } @@ -862,19 +867,44 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 rpstat; + u32 rpupei, rpcurup, rpprevup; + u32 rpdownei, rpcurdown, rpprevdown; int max_freq; /* RPSTAT1 is in the GT power well */ __gen6_gt_force_wake_get(dev_priv); + rpstat = I915_READ(GEN6_RPSTAT1); + rpupei = I915_READ(GEN6_RP_CUR_UP_EI); + rpcurup = I915_READ(GEN6_RP_CUR_UP); + rpprevup = I915_READ(GEN6_RP_PREV_UP); + rpdownei = I915_READ(GEN6_RP_CUR_DOWN_EI); + rpcurdown = I915_READ(GEN6_RP_CUR_DOWN); + rpprevdown = I915_READ(GEN6_RP_PREV_DOWN); + seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status); - seq_printf(m, "RPSTAT1: 0x%08x\n", I915_READ(GEN6_RPSTAT1)); + seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat); seq_printf(m, "Render p-state ratio: %d\n", (gt_perf_status & 0xff00) >> 8); seq_printf(m, "Render p-state VID: %d\n", gt_perf_status & 0xff); seq_printf(m, "Render p-state limit: %d\n", rp_state_limits & 0xff); + seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >> + GEN6_CAGF_SHIFT) * 100); + seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & + GEN6_CURICONT_MASK); + seq_printf(m, "RP CUR UP: %dus\n", rpcurup & + GEN6_CURBSYTAVG_MASK); + seq_printf(m, "RP PREV UP: %dus\n", rpprevup & + GEN6_CURBSYTAVG_MASK); + seq_printf(m, "RP CUR DOWN EI: %dus\n", rpdownei & + GEN6_CURIAVG_MASK); + seq_printf(m, "RP CUR DOWN: %dus\n", rpcurdown & + GEN6_CURBSYTAVG_MASK); + seq_printf(m, "RP PREV DOWN: %dus\n", rpprevdown & + GEN6_CURBSYTAVG_MASK); max_freq = (rp_state_cap & 0xff0000) >> 16; seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", @@ -1259,7 +1289,7 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor) } static struct drm_info_list i915_debugfs_list[] = { - {"i915_capabilities", i915_capabilities, 0, 0}, + {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, {"i915_gem_gtt", i915_gem_gtt_info, 0}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index e33d9be7df3..72730377a01 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -43,6 +43,17 @@ #include <linux/slab.h> #include <acpi/video.h> +static void i915_write_hws_pga(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + u32 addr; + + addr = dev_priv->status_page_dmah->busaddr; + if (INTEL_INFO(dev)->gen >= 4) + addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0; + I915_WRITE(HWS_PGA, addr); +} + /** * Sets up the hardware status page for devices that need a physical address * in the register. @@ -60,16 +71,13 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; - dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr; + ring->status_page.page_addr = + (void __force __iomem *)dev_priv->status_page_dmah->vaddr; - memset(ring->status_page.page_addr, 0, PAGE_SIZE); + memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); - if (INTEL_INFO(dev)->gen >= 4) - dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) & - 0xf0; + i915_write_hws_pga(dev); - I915_WRITE(HWS_PGA, dev_priv->dma_status_page); DRM_DEBUG_DRIVER("Enabled hardware status page\n"); return 0; } @@ -216,7 +224,7 @@ static int i915_dma_resume(struct drm_device * dev) if (ring->status_page.gfx_addr != 0) intel_ring_setup_status_page(ring); else - I915_WRITE(HWS_PGA, dev_priv->dma_status_page); + i915_write_hws_pga(dev); DRM_DEBUG_DRIVER("Enabled hardware status page\n"); @@ -771,6 +779,9 @@ static int i915_getparam(struct drm_device *dev, void *data, case I915_PARAM_HAS_EXEC_CONSTANTS: value = INTEL_INFO(dev)->gen >= 4; break; + case I915_PARAM_HAS_RELAXED_DELTA: + value = 1; + break; default: DRM_DEBUG_DRIVER("Unknown parameter %d\n", param->param); @@ -859,8 +870,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data, " G33 hw status page\n"); return -ENOMEM; } - ring->status_page.page_addr = dev_priv->hws_map.handle; - memset(ring->status_page.page_addr, 0, PAGE_SIZE); + ring->status_page.page_addr = + (void __force __iomem *)dev_priv->hws_map.handle; + memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); I915_WRITE(HWS_PGA, ring->status_page.gfx_addr); DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n", @@ -2013,9 +2025,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->error_lock); - dev_priv->trace_irq_seqno = 0; - ret = drm_vblank_init(dev, I915_NUM_PIPE); + if (IS_MOBILE(dev) || !IS_GEN2(dev)) + dev_priv->num_pipe = 2; + else + dev_priv->num_pipe = 1; + + ret = drm_vblank_init(dev, dev_priv->num_pipe); if (ret) goto out_gem_unload; diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 22ec066adae..3dba19f28e4 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -43,10 +43,13 @@ module_param_named(modeset, i915_modeset, int, 0400); unsigned int i915_fbpercrtc = 0; module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); +int i915_panel_ignore_lid = 0; +module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); + unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); -unsigned int i915_semaphores = 0; +unsigned int i915_semaphores = 1; module_param_named(semaphores, i915_semaphores, int, 0600); unsigned int i915_enable_rc6 = 0; @@ -58,7 +61,10 @@ module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400); unsigned int i915_panel_use_ssc = 1; module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); -bool i915_try_reset = true; +int i915_vbt_sdvo_panel_type = -1; +module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600); + +static bool i915_try_reset = true; module_param_named(reset, i915_try_reset, bool, 0600); static struct drm_driver driver; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 456f4048483..b68abf19bce 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -49,17 +49,22 @@ enum pipe { PIPE_A = 0, PIPE_B, + PIPE_C, + I915_MAX_PIPES }; +#define pipe_name(p) ((p) + 'A') enum plane { PLANE_A = 0, PLANE_B, + PLANE_C, }; - -#define I915_NUM_PIPE 2 +#define plane_name(p) ((p) + 'A') #define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT)) +#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++) + /* Interface history: * * 1.1: Original. @@ -75,10 +80,7 @@ enum plane { #define DRIVER_PATCHLEVEL 0 #define WATCH_COHERENCY 0 -#define WATCH_EXEC 0 -#define WATCH_RELOC 0 #define WATCH_LISTS 0 -#define WATCH_PWRITE 0 #define I915_GEM_PHYS_CURSOR_0 1 #define I915_GEM_PHYS_CURSOR_1 2 @@ -111,6 +113,7 @@ struct intel_opregion { struct opregion_swsci *swsci; struct opregion_asle *asle; void *vbt; + u32 __iomem *lid_state; }; #define OPREGION_SIZE (8*1024) @@ -144,8 +147,7 @@ struct intel_display_error_state; struct drm_i915_error_state { u32 eir; u32 pgtbl_er; - u32 pipeastat; - u32 pipebstat; + u32 pipestat[I915_MAX_PIPES]; u32 ipeir; u32 ipehr; u32 instdone; @@ -172,7 +174,7 @@ struct drm_i915_error_state { int page_count; u32 gtt_offset; u32 *pages[0]; - } *ringbuffer, *batchbuffer[I915_NUM_RINGS]; + } *ringbuffer[I915_NUM_RINGS], *batchbuffer[I915_NUM_RINGS]; struct drm_i915_error_buffer { u32 size; u32 name; @@ -200,9 +202,7 @@ struct drm_i915_display_funcs { void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); - void (*update_wm)(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int sr_htotal, - int pixel_size); + void (*update_wm)(struct drm_device *dev); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -274,7 +274,6 @@ typedef struct drm_i915_private { uint32_t next_seqno; drm_dma_handle_t *status_page_dmah; - dma_addr_t dma_status_page; uint32_t counter; drm_local_map_t hws_map; struct drm_i915_gem_object *pwrctx; @@ -289,7 +288,6 @@ typedef struct drm_i915_private { int page_flipping; atomic_t irq_received; - u32 trace_irq_seqno; /* protects the irq masks */ spinlock_t irq_lock; @@ -324,8 +322,6 @@ typedef struct drm_i915_private { int cfb_plane; int cfb_y; - int irq_enabled; - struct intel_opregion opregion; /* overlay */ @@ -387,7 +383,6 @@ typedef struct drm_i915_private { u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; - u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; @@ -615,6 +610,12 @@ typedef struct drm_i915_private { 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. * @@ -652,6 +653,7 @@ typedef struct drm_i915_private { unsigned int lvds_border_bits; /* Panel fitter placement and size for Ironlake+ */ u32 pch_pf_pos, pch_pf_size; + int panel_t3, panel_t12; struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2]; @@ -698,6 +700,8 @@ typedef struct drm_i915_private { /* list of fbdev register on this device */ struct intel_fbdev *fbdev; + + struct drm_property *broadcast_rgb_property; } drm_i915_private_t; struct drm_i915_gem_object { @@ -955,10 +959,12 @@ enum intel_chip_family { extern struct drm_ioctl_desc i915_ioctls[]; extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc; +extern int i915_panel_ignore_lid; extern unsigned int i915_powersave; extern unsigned int i915_semaphores; extern unsigned int i915_lvds_downclock; extern unsigned int i915_panel_use_ssc; +extern int i915_vbt_sdvo_panel_type; extern unsigned int i915_enable_rc6; extern int i915_suspend(struct drm_device *dev, pm_message_t state); @@ -998,8 +1004,6 @@ extern int i915_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int i915_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); -void i915_trace_irq_get(struct drm_device *dev, u32 seqno); -extern void i915_enable_interrupt (struct drm_device *dev); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(struct drm_device * dev); @@ -1051,7 +1055,6 @@ extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, struct mem_block *heap); /* i915_gem.c */ -int i915_gem_check_is_wedged(struct drm_device *dev); int i915_gem_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_create_ioctl(struct drm_device *dev, void *data, @@ -1094,8 +1097,7 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_load(struct drm_device *dev); int i915_gem_init_object(struct drm_gem_object *obj); -int __must_check i915_gem_flush_ring(struct drm_device *dev, - struct intel_ring_buffer *ring, +int __must_check i915_gem_flush_ring(struct intel_ring_buffer *ring, uint32_t invalidate_domains, uint32_t flush_domains); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, @@ -1110,8 +1112,7 @@ void i915_gem_release_mmap(struct drm_i915_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); -int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj, - bool interruptible); +int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj); void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj, struct intel_ring_buffer *ring, u32 seqno); @@ -1126,16 +1127,14 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2) } static inline u32 -i915_gem_next_request_seqno(struct drm_device *dev, - struct intel_ring_buffer *ring) +i915_gem_next_request_seqno(struct intel_ring_buffer *ring) { - drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_private_t *dev_priv = ring->dev->dev_private; return ring->outstanding_lazy_request = dev_priv->next_seqno; } int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj, - struct intel_ring_buffer *pipelined, - bool interruptible); + struct intel_ring_buffer *pipelined); int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); @@ -1144,8 +1143,7 @@ void i915_gem_clflush_object(struct drm_i915_gem_object *obj); int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj, uint32_t read_domains, uint32_t write_domain); -int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj, - bool interruptible); +int __must_check i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj); int __must_check i915_gem_init_ringbuffer(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); void i915_gem_do_init(struct drm_device *dev, @@ -1154,14 +1152,11 @@ void i915_gem_do_init(struct drm_device *dev, unsigned long end); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_idle(struct drm_device *dev); -int __must_check i915_add_request(struct drm_device *dev, - struct drm_file *file_priv, - struct drm_i915_gem_request *request, - struct intel_ring_buffer *ring); -int __must_check i915_do_wait_request(struct drm_device *dev, - uint32_t seqno, - bool interruptible, - struct intel_ring_buffer *ring); +int __must_check i915_add_request(struct intel_ring_buffer *ring, + struct drm_file *file, + struct drm_i915_gem_request *request); +int __must_check i915_wait_request(struct intel_ring_buffer *ring, + uint32_t seqno); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int __must_check i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, @@ -1313,7 +1308,7 @@ extern void intel_display_print_error_state(struct seq_file *m, #define __i915_read(x, y) \ static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ u##x val = read##y(dev_priv->regs + reg); \ - trace_i915_reg_rw('R', reg, val, sizeof(val)); \ + trace_i915_reg_rw(false, reg, val, sizeof(val)); \ return val; \ } __i915_read(8, b) @@ -1324,7 +1319,7 @@ __i915_read(64, q) #define __i915_write(x, y) \ static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \ - trace_i915_reg_rw('W', reg, val, sizeof(val)); \ + trace_i915_reg_rw(true, reg, val, sizeof(val)); \ write##y(val, dev_priv->regs + reg); \ } __i915_write(8, b) @@ -1382,47 +1377,4 @@ static inline void i915_gt_write(struct drm_i915_private *dev_priv, __gen6_gt_wait_for_fifo(dev_priv); I915_WRITE(reg, val); } - -static inline void -i915_write(struct drm_i915_private *dev_priv, u32 reg, u64 val, int len) -{ - /* Trace down the write operation before the real write */ - trace_i915_reg_rw('W', reg, val, len); - switch (len) { - case 8: - writeq(val, dev_priv->regs + reg); - break; - case 4: - writel(val, dev_priv->regs + reg); - break; - case 2: - writew(val, dev_priv->regs + reg); - break; - case 1: - writeb(val, dev_priv->regs + reg); - break; - } -} - -/** - * 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 - * MI_STORE_DATA_IMM. - * - * The following dwords have a reserved meaning: - * 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes. - * 0x04: ring 0 head pointer - * 0x05: ring 1 head pointer (915-class) - * 0x06: ring 2 head pointer (915-class) - * 0x10-0x1b: Context status DWords (GM45) - * 0x1f: Last written status offset. (GM45) - * - * The area from dword 0x20 to 0x3ff is available for driver usage. - */ -#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\ - (LP_RING(dev_priv)->status_page.page_addr))[reg]) -#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX) -#define I915_GEM_HWS_INDEX 0x20 -#define I915_BREADCRUMB_INDEX 0x21 - #endif diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 36e66cc5225..950a5ab921a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -75,8 +75,8 @@ static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv, dev_priv->mm.object_memory -= size; } -int -i915_gem_check_is_wedged(struct drm_device *dev) +static int +i915_gem_wait_for_error(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct completion *x = &dev_priv->error_completion; @@ -90,27 +90,24 @@ i915_gem_check_is_wedged(struct drm_device *dev) if (ret) return ret; - /* Success, we reset the GPU! */ - if (!atomic_read(&dev_priv->mm.wedged)) - return 0; - - /* 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. - */ - spin_lock_irqsave(&x->wait.lock, flags); - x->done++; - spin_unlock_irqrestore(&x->wait.lock, flags); - return -EIO; + 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. + */ + spin_lock_irqsave(&x->wait.lock, flags); + x->done++; + spin_unlock_irqrestore(&x->wait.lock, flags); + } + 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_check_is_wedged(dev); + ret = i915_gem_wait_for_error(dev); if (ret) return ret; @@ -118,11 +115,6 @@ int i915_mutex_lock_interruptible(struct drm_device *dev) if (ret) return ret; - if (atomic_read(&dev_priv->mm.wedged)) { - mutex_unlock(&dev->struct_mutex); - return -EAGAIN; - } - WARN_ON(i915_verify_lists(dev)); return 0; } @@ -514,7 +506,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -526,6 +518,8 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, goto out; } + trace_i915_gem_object_pread(obj, args->offset, args->size); + ret = i915_gem_object_set_cpu_read_domain_range(obj, args->offset, args->size); @@ -955,7 +949,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -967,6 +961,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, goto out; } + trace_i915_gem_object_pwrite(obj, args->offset, args->size); + /* We can only do the GTT pwrite on untiled buffers, as otherwise * it would end up going through the fenced access, and we'll get * different detiling behavior between reading and writing. @@ -1049,7 +1045,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -1092,7 +1088,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle)); - if (obj == NULL) { + if (&obj->base == NULL) { ret = -ENOENT; goto unlock; } @@ -1121,7 +1117,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_mmap *args = data; struct drm_gem_object *obj; - loff_t offset; unsigned long addr; if (!(dev->driver->driver_features & DRIVER_GEM)) @@ -1136,8 +1131,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data, return -E2BIG; } - offset = args->offset; - down_write(¤t->mm->mmap_sem); addr = do_mmap(obj->filp, 0, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, @@ -1182,9 +1175,13 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - /* Now bind it into the GTT if needed */ - mutex_lock(&dev->struct_mutex); + ret = i915_mutex_lock_interruptible(dev); + if (ret) + goto out; + + trace_i915_gem_object_fault(obj, page_offset, true, write); + /* Now bind it into the GTT if needed */ if (!obj->map_and_fenceable) { ret = i915_gem_object_unbind(obj); if (ret) @@ -1203,7 +1200,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (obj->tiling_mode == I915_TILING_NONE) ret = i915_gem_object_put_fence(obj); else - ret = i915_gem_object_get_fence(obj, NULL, true); + ret = i915_gem_object_get_fence(obj, NULL); if (ret) goto unlock; @@ -1219,12 +1216,21 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); unlock: mutex_unlock(&dev->struct_mutex); - +out: switch (ret) { + case -EIO: 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: return VM_FAULT_NOPAGE; case -ENOMEM: return VM_FAULT_OOM; @@ -1457,7 +1463,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, return ret; obj = to_intel_bo(drm_gem_obj |