static void direct_interrupts_to_host(struct drm_i915_private *dev_priv) { struct intel_engine_cs *ring; int i, irqs; /* tell all command streamers NOT to forward interrupts and vblank to GuC */ irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER); irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING); for_each_ring(ring, dev_priv, i) I915_WRITE(RING_MODE_GEN7(ring), irqs); /* route all GT interrupts to the host */ I915_WRITE(GUC_BCS_RCS_IER, 0); I915_WRITE(GUC_VCS2_VCS1_IER, 0); I915_WRITE(GUC_WD_VECS_IER, 0); }
static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv) { struct intel_engine_cs *ring; int i, irqs; /* tell all command streamers to forward interrupts and vblank to GuC */ irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_ALWAYS); irqs |= _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING); for_each_ring(ring, dev_priv, i) I915_WRITE(RING_MODE_GEN7(ring), irqs); /* route USER_INTERRUPT to Host, all others are sent to GuC. */ irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT | GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT; /* These three registers have the same bit definitions */ I915_WRITE(GUC_BCS_RCS_IER, ~irqs); I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs); I915_WRITE(GUC_WD_VECS_IER, ~irqs); }
/** * Once we have scheduled commands on GPU, it might take a while GPU * to execute them. Following is done to make sure Gfx is in D0i0 while * GPU is executing the commands. * 1. For IOCTLS make sure we are in D0i0 by calling "get_ioctl". * 2. if IOCTL scheudles GPU commands using rings do the following * a. For all ring accesses make sure we add a request in the request * list and schedule a work item to track the "seq no". This * is done by using "i915_add_request" or "i915_add_request_no_flush" * functions. * b. If request list was empty, we do a "get_ring". This will increment * ref count to make sure GPU will be in D0 state. * c. Once the list becomes empty call put_ring * * Note: All the ring accesses are covered with struct_mutex. So we * don't need any synchronization to protect ring_active. */ int i915_rpm_get_ring(struct drm_device *drm_dev) { struct intel_engine_cs *ring; struct drm_i915_private *dev_priv = drm_dev->dev_private; int i; bool idle = true; for_each_ring(ring, dev_priv, i) idle &= list_empty(&ring->request_list); if (idle) { if (!dev_priv->rpm.ring_active) { dev_priv->rpm.ring_active = true; pm_runtime_get_noresume(drm_dev->dev); } } return 0; }
/** * i915_reset - reset chip after a hang * @dev: drm device to reset * * Reset the chip. Useful if a hang is detected. Returns zero on successful * reset or otherwise an error code. * * Procedure is fairly simple: * - reset the chip using the reset reg * - re-init context state * - re-init hardware status page * - re-init ring buffer * - re-init interrupt state * - re-init display */ int i915_reset(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; int ret; if (!i915_try_reset) return 0; mutex_lock(&dev->struct_mutex); i915_gem_reset(dev); ret = -ENODEV; if (get_seconds() - dev_priv->last_gpu_reset < 5) DRM_ERROR("GPU hanging too fast, declaring wedged!\n"); else ret = intel_gpu_reset(dev); dev_priv->last_gpu_reset = get_seconds(); if (ret) { DRM_ERROR("Failed to reset chip.\n"); mutex_unlock(&dev->struct_mutex); return ret; } /* Ok, now get things going again... */ /* * Everything depends on having the GTT running, so we need to start * there. Fortunately we don't need to do this unless we reset the * chip at a PCI level. * * Next we need to restore the context, but we don't use those * yet either... * * Ring buffer needs to be re-initialized in the KMS case, or if X * was running at the time of the reset (i.e. we weren't VT * switched away). */ if (drm_core_check_feature(dev, DRIVER_MODESET) || !dev_priv->mm.suspended) { struct intel_ring_buffer *ring; int i; dev_priv->mm.suspended = 0; i915_gem_init_swizzling(dev); for_each_ring(ring, dev_priv, i) ring->init(ring); i915_gem_context_init(dev); i915_gem_init_ppgtt(dev); /* * It would make sense to re-init all the other hw state, at * least the rps/rc6/emon init done within modeset_init_hw. For * some unknown reason, this blows up my ilk, so don't. */ mutex_unlock(&dev->struct_mutex); drm_irq_uninstall(dev); drm_irq_install(dev); } else { mutex_unlock(&dev->struct_mutex); } return 0; }
int i915_error_state_to_str(struct drm_i915_error_state_buf *m, const struct i915_error_state_file_priv *error_priv) { struct drm_device *dev = error_priv->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_error_state *error = error_priv->error; struct intel_ring_buffer *ring; int i, j, page, offset, elt; if (!error) { err_printf(m, "no error state collected\n"); goto out; } err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec, error->time.tv_usec); err_printf(m, "Kernel: " UTS_RELEASE "\n"); err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device); err_printf(m, "EIR: 0x%08x\n", error->eir); err_printf(m, "IER: 0x%08x\n", error->ier); err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er); err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake); err_printf(m, "DERRMR: 0x%08x\n", error->derrmr); err_printf(m, "CCID: 0x%08x\n", error->ccid); for (i = 0; i < dev_priv->num_fence_regs; i++) err_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]); for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++) err_printf(m, " INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]); if (INTEL_INFO(dev)->gen >= 6) { err_printf(m, "ERROR: 0x%08x\n", error->error); err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg); } if (INTEL_INFO(dev)->gen == 7) err_printf(m, "ERR_INT: 0x%08x\n", error->err_int); for_each_ring(ring, dev_priv, i) i915_ring_error_state(m, dev, error, i); if (error->active_bo) print_error_buffers(m, "Active", error->active_bo[0], error->active_bo_count[0]); if (error->pinned_bo) print_error_buffers(m, "Pinned", error->pinned_bo[0], error->pinned_bo_count[0]); for (i = 0; i < ARRAY_SIZE(error->ring); i++) { struct drm_i915_error_object *obj; if ((obj = error->ring[i].batchbuffer)) { err_printf(m, "%s --- gtt_offset = 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++) { err_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); offset += 4; } } } if (error->ring[i].num_requests) { err_printf(m, "%s --- %d requests\n", dev_priv->ring[i].name, error->ring[i].num_requests); for (j = 0; j < error->ring[i].num_requests; j++) { err_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n", error->ring[i].requests[j].seqno, error->ring[i].requests[j].jiffies, error->ring[i].requests[j].tail); } } if ((obj = error->ring[i].ringbuffer)) { err_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++) { err_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]); offset += 4; } } } obj = error->ring[i].ctx; if (obj) { err_printf(m, "%s --- HW Context = 0x%08x\n", dev_priv->ring[i].name, obj->gtt_offset); offset = 0; for (elt = 0; elt < PAGE_SIZE/16; elt += 4) { err_printf(m, "[%04x] %08x %08x %08x %08x\n", offset, obj->pages[0][elt], obj->pages[0][elt+1], obj->pages[0][elt+2], obj->pages[0][elt+3]); offset += 16; } } } if (error->overlay) intel_overlay_print_error_state(m, error->overlay); if (error->display) intel_display_print_error_state(m, dev, error->display); out: if (m->bytes == 0 && m->err) return m->err; return 0; }