Commit ee4b6faf authored by Mika Kuoppala's avatar Mika Kuoppala Committed by Mika Kuoppala

drm/i915: Modify reset func to handle per engine resets

In full gpu reset we prime all engines and reset domains corresponding to
each engine. Per engine reset is just a special case of this process
wherein only a single engine is reset. This change is aimed to modify
relevant functions to achieve this. There are some other steps we carry out
in case of engine reset which are addressed in later patches.

Reset func now accepts a mask of all engines that need to be reset. Where
per engine resets are supported, error handler populates the mask
accordingly otherwise all engines are specified.

v2: ALL_ENGINES mask fixup, better for_each_ring_masked (Chris)
v3: Whitespace fixes (Chris)
v4: Rebase due to s/ring/engine

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
Signed-off-by: default avatarArun Siluvery <arun.siluvery@linux.intel.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarMika Kuoppala <mika.kuoppala@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1458143640-20563-1-git-send-email-mika.kuoppala@intel.com
parent 72341af4
...@@ -881,7 +881,7 @@ int i915_reset(struct drm_device *dev) ...@@ -881,7 +881,7 @@ int i915_reset(struct drm_device *dev)
simulated = dev_priv->gpu_error.stop_rings != 0; simulated = dev_priv->gpu_error.stop_rings != 0;
ret = intel_gpu_reset(dev); ret = intel_gpu_reset(dev, ALL_ENGINES);
/* Also reset the gpu hangman. */ /* Also reset the gpu hangman. */
if (simulated) { if (simulated) {
......
...@@ -1988,6 +1988,10 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc) ...@@ -1988,6 +1988,10 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc)
for ((i__) = 0; (i__) < I915_NUM_ENGINES; (i__)++) \ for ((i__) = 0; (i__) < I915_NUM_ENGINES; (i__)++) \
for_each_if ((((ring__) = &(dev_priv__)->engine[(i__)]), intel_engine_initialized((ring__)))) for_each_if ((((ring__) = &(dev_priv__)->engine[(i__)]), intel_engine_initialized((ring__))))
#define for_each_engine_masked(engine__, dev_priv__, mask__) \
for ((engine__) = &dev_priv->engine[0]; (engine__) < &dev_priv->engine[I915_NUM_ENGINES]; (engine__)++) \
for_each_if (intel_engine_flag((engine__)) & (mask__) && intel_engine_initialized((engine__)))
enum hdmi_force_audio { enum hdmi_force_audio {
HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */ HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
HDMI_AUDIO_OFF, /* force turn off HDMI audio */ HDMI_AUDIO_OFF, /* force turn off HDMI audio */
...@@ -2570,6 +2574,8 @@ struct drm_i915_cmd_table { ...@@ -2570,6 +2574,8 @@ struct drm_i915_cmd_table {
#define BLT_RING (1<<BCS) #define BLT_RING (1<<BCS)
#define VEBOX_RING (1<<VECS) #define VEBOX_RING (1<<VECS)
#define BSD2_RING (1<<VCS2) #define BSD2_RING (1<<VCS2)
#define ALL_ENGINES (~0)
#define HAS_BSD(dev) (INTEL_INFO(dev)->ring_mask & BSD_RING) #define HAS_BSD(dev) (INTEL_INFO(dev)->ring_mask & BSD_RING)
#define HAS_BSD2(dev) (INTEL_INFO(dev)->ring_mask & BSD2_RING) #define HAS_BSD2(dev) (INTEL_INFO(dev)->ring_mask & BSD2_RING)
#define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING) #define HAS_BLT(dev) (INTEL_INFO(dev)->ring_mask & BLT_RING)
...@@ -2698,7 +2704,7 @@ extern void i915_driver_postclose(struct drm_device *dev, ...@@ -2698,7 +2704,7 @@ extern void i915_driver_postclose(struct drm_device *dev,
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
#endif #endif
extern int intel_gpu_reset(struct drm_device *dev); extern int intel_gpu_reset(struct drm_device *dev, u32 engine_mask);
extern bool intel_has_gpu_reset(struct drm_device *dev); extern bool intel_has_gpu_reset(struct drm_device *dev);
extern int i915_reset(struct drm_device *dev); extern int i915_reset(struct drm_device *dev);
extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
......
...@@ -5018,7 +5018,7 @@ i915_gem_cleanup_engines(struct drm_device *dev) ...@@ -5018,7 +5018,7 @@ i915_gem_cleanup_engines(struct drm_device *dev)
* expects the system to be in execlists mode on startup, * expects the system to be in execlists mode on startup,
* so we need to reset the GPU back to legacy mode. * so we need to reset the GPU back to legacy mode.
*/ */
intel_gpu_reset(dev); intel_gpu_reset(dev, ALL_ENGINES);
} }
static void static void
......
...@@ -413,7 +413,7 @@ void i915_gem_context_fini(struct drm_device *dev) ...@@ -413,7 +413,7 @@ void i915_gem_context_fini(struct drm_device *dev)
/* The only known way to stop the gpu from accessing the hw context is /* The only known way to stop the gpu from accessing the hw context is
* to reset it. Do this as the very last operation to avoid confusing * to reset it. Do this as the very last operation to avoid confusing
* other code, leading to spurious errors. */ * other code, leading to spurious errors. */
intel_gpu_reset(dev); intel_gpu_reset(dev, ALL_ENGINES);
/* When default context is created and switched to, base object refcount /* When default context is created and switched to, base object refcount
* will be 2 (+1 from object creation and +1 from do_switch()). * will be 2 (+1 from object creation and +1 from do_switch()).
......
...@@ -164,6 +164,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg) ...@@ -164,6 +164,8 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
#define GEN6_GRDOM_RENDER (1 << 1) #define GEN6_GRDOM_RENDER (1 << 1)
#define GEN6_GRDOM_MEDIA (1 << 2) #define GEN6_GRDOM_MEDIA (1 << 2)
#define GEN6_GRDOM_BLT (1 << 3) #define GEN6_GRDOM_BLT (1 << 3)
#define GEN6_GRDOM_VECS (1 << 4)
#define GEN8_GRDOM_MEDIA2 (1 << 7)
#define RING_PP_DIR_BASE(ring) _MMIO((ring)->mmio_base+0x228) #define RING_PP_DIR_BASE(ring) _MMIO((ring)->mmio_base+0x228)
#define RING_PP_DIR_BASE_READ(ring) _MMIO((ring)->mmio_base+0x518) #define RING_PP_DIR_BASE_READ(ring) _MMIO((ring)->mmio_base+0x518)
......
...@@ -1433,7 +1433,7 @@ static int i915_reset_complete(struct drm_device *dev) ...@@ -1433,7 +1433,7 @@ static int i915_reset_complete(struct drm_device *dev)
return (gdrst & GRDOM_RESET_STATUS) == 0; return (gdrst & GRDOM_RESET_STATUS) == 0;
} }
static int i915_do_reset(struct drm_device *dev) static int i915_do_reset(struct drm_device *dev, unsigned engine_mask)
{ {
/* assert reset for at least 20 usec */ /* assert reset for at least 20 usec */
pci_write_config_byte(dev->pdev, I915_GDRST, GRDOM_RESET_ENABLE); pci_write_config_byte(dev->pdev, I915_GDRST, GRDOM_RESET_ENABLE);
...@@ -1450,13 +1450,13 @@ static int g4x_reset_complete(struct drm_device *dev) ...@@ -1450,13 +1450,13 @@ static int g4x_reset_complete(struct drm_device *dev)
return (gdrst & GRDOM_RESET_ENABLE) == 0; return (gdrst & GRDOM_RESET_ENABLE) == 0;
} }
static int g33_do_reset(struct drm_device *dev) static int g33_do_reset(struct drm_device *dev, unsigned engine_mask)
{ {
pci_write_config_byte(dev->pdev, I915_GDRST, GRDOM_RESET_ENABLE); pci_write_config_byte(dev->pdev, I915_GDRST, GRDOM_RESET_ENABLE);
return wait_for(g4x_reset_complete(dev), 500); return wait_for(g4x_reset_complete(dev), 500);
} }
static int g4x_do_reset(struct drm_device *dev) static int g4x_do_reset(struct drm_device *dev, unsigned engine_mask)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int ret; int ret;
...@@ -1486,7 +1486,7 @@ static int g4x_do_reset(struct drm_device *dev) ...@@ -1486,7 +1486,7 @@ static int g4x_do_reset(struct drm_device *dev)
return 0; return 0;
} }
static int ironlake_do_reset(struct drm_device *dev) static int ironlake_do_reset(struct drm_device *dev, unsigned engine_mask)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int ret; int ret;
...@@ -1510,21 +1510,62 @@ static int ironlake_do_reset(struct drm_device *dev) ...@@ -1510,21 +1510,62 @@ static int ironlake_do_reset(struct drm_device *dev)
return 0; return 0;
} }
static int gen6_do_reset(struct drm_device *dev) /* Reset the hardware domains (GENX_GRDOM_*) specified by mask */
static int gen6_hw_domain_reset(struct drm_i915_private *dev_priv,
u32 hw_domain_mask)
{ {
struct drm_i915_private *dev_priv = dev->dev_private;
int ret; int ret;
/* Reset the chip */
/* GEN6_GDRST is not in the gt power well, no need to check /* GEN6_GDRST is not in the gt power well, no need to check
* for fifo space for the write or forcewake the chip for * for fifo space for the write or forcewake the chip for
* the read * the read
*/ */
__raw_i915_write32(dev_priv, GEN6_GDRST, GEN6_GRDOM_FULL); __raw_i915_write32(dev_priv, GEN6_GDRST, hw_domain_mask);
#define ACKED ((__raw_i915_read32(dev_priv, GEN6_GDRST) & hw_domain_mask) == 0)
/* Spin waiting for the device to ack the reset requests */
ret = wait_for(ACKED, 500);
#undef ACKED
return ret;
}
/**
* gen6_reset_engines - reset individual engines
* @dev: DRM device
* @engine_mask: mask of intel_ring_flag() engines or ALL_ENGINES for full reset
*
* This function will reset the individual engines that are set in engine_mask.
* If you provide ALL_ENGINES as mask, full global domain reset will be issued.
*
* Note: It is responsibility of the caller to handle the difference between
* asking full domain reset versus reset for all available individual engines.
*
* Returns 0 on success, nonzero on error.
*/
static int gen6_reset_engines(struct drm_device *dev, unsigned engine_mask)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *engine;
const u32 hw_engine_mask[I915_NUM_ENGINES] = {
[RCS] = GEN6_GRDOM_RENDER,
[BCS] = GEN6_GRDOM_BLT,
[VCS] = GEN6_GRDOM_MEDIA,
[VCS2] = GEN8_GRDOM_MEDIA2,
[VECS] = GEN6_GRDOM_VECS,
};
u32 hw_mask;
int ret;
/* Spin waiting for the device to ack the reset request */ if (engine_mask == ALL_ENGINES) {
ret = wait_for((__raw_i915_read32(dev_priv, GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500); hw_mask = GEN6_GRDOM_FULL;
} else {
hw_mask = 0;
for_each_engine_masked(engine, dev_priv, engine_mask)
hw_mask |= hw_engine_mask[engine->id];
}
ret = gen6_hw_domain_reset(dev_priv, hw_mask);
intel_uncore_forcewake_reset(dev, true); intel_uncore_forcewake_reset(dev, true);
...@@ -1567,34 +1608,34 @@ static void gen8_unrequest_engine_reset(struct intel_engine_cs *engine) ...@@ -1567,34 +1608,34 @@ static void gen8_unrequest_engine_reset(struct intel_engine_cs *engine)
_MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET)); _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET));
} }
static int gen8_do_reset(struct drm_device *dev) static int gen8_reset_engines(struct drm_device *dev, unsigned engine_mask)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *engine; struct intel_engine_cs *engine;
int i;
for_each_engine(engine, dev_priv, i) for_each_engine_masked(engine, dev_priv, engine_mask)
if (gen8_request_engine_reset(engine)) if (gen8_request_engine_reset(engine))
goto not_ready; goto not_ready;
return gen6_do_reset(dev); return gen6_reset_engines(dev, engine_mask);
not_ready: not_ready:
for_each_engine(engine, dev_priv, i) for_each_engine_masked(engine, dev_priv, engine_mask)
gen8_unrequest_engine_reset(engine); gen8_unrequest_engine_reset(engine);
return -EIO; return -EIO;
} }
static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *,
unsigned engine_mask)
{ {
if (!i915.reset) if (!i915.reset)
return NULL; return NULL;
if (INTEL_INFO(dev)->gen >= 8) if (INTEL_INFO(dev)->gen >= 8)
return gen8_do_reset; return gen8_reset_engines;
else if (INTEL_INFO(dev)->gen >= 6) else if (INTEL_INFO(dev)->gen >= 6)
return gen6_do_reset; return gen6_reset_engines;
else if (IS_GEN5(dev)) else if (IS_GEN5(dev))
return ironlake_do_reset; return ironlake_do_reset;
else if (IS_G4X(dev)) else if (IS_G4X(dev))
...@@ -1607,10 +1648,10 @@ static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) ...@@ -1607,10 +1648,10 @@ static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *)
return NULL; return NULL;
} }
int intel_gpu_reset(struct drm_device *dev) int intel_gpu_reset(struct drm_device *dev, unsigned engine_mask)
{ {
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
int (*reset)(struct drm_device *); int (*reset)(struct drm_device *, unsigned);
int ret; int ret;
reset = intel_get_gpu_reset(dev); reset = intel_get_gpu_reset(dev);
...@@ -1621,7 +1662,7 @@ int intel_gpu_reset(struct drm_device *dev) ...@@ -1621,7 +1662,7 @@ int intel_gpu_reset(struct drm_device *dev)
* request may be dropped and never completes (causing -EIO). * request may be dropped and never completes (causing -EIO).
*/ */
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
ret = reset(dev); ret = reset(dev, engine_mask);
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment