summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/gpu/drm/i915/intel_uncore.c
diff options
context:
space:
mode:
authorJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-11 10:41:07 +0300
committerJosé Pekkarinen <jose.pekkarinen@nokia.com>2016-04-13 08:17:18 +0300
commite09b41010ba33a20a87472ee821fa407a5b8da36 (patch)
treed10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/gpu/drm/i915/intel_uncore.c
parentf93b97fd65072de626c074dbe099a1fff05ce060 (diff)
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page. During the rebasing, the following patch collided: Force tick interrupt and get rid of softirq magic(I70131fb85). Collisions have been removed because its logic was found on the source already. Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769 Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/gpu/drm/i915/intel_uncore.c')
-rw-r--r--kernel/drivers/gpu/drm/i915/intel_uncore.c219
1 files changed, 172 insertions, 47 deletions
diff --git a/kernel/drivers/gpu/drm/i915/intel_uncore.c b/kernel/drivers/gpu/drm/i915/intel_uncore.c
index a18807ec8..43cba129a 100644
--- a/kernel/drivers/gpu/drm/i915/intel_uncore.c
+++ b/kernel/drivers/gpu/drm/i915/intel_uncore.c
@@ -27,7 +27,7 @@
#include <linux/pm_runtime.h>
-#define FORCEWAKE_ACK_TIMEOUT_MS 2
+#define FORCEWAKE_ACK_TIMEOUT_MS 50
#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__))
@@ -52,8 +52,7 @@ static const char * const forcewake_domain_names[] = {
const char *
intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id)
{
- BUILD_BUG_ON((sizeof(forcewake_domain_names)/sizeof(const char *)) !=
- FW_DOMAIN_ID_COUNT);
+ BUILD_BUG_ON(ARRAY_SIZE(forcewake_domain_names) != FW_DOMAIN_ID_COUNT);
if (id >= 0 && id < FW_DOMAIN_ID_COUNT)
return forcewake_domain_names[id];
@@ -383,6 +382,26 @@ void intel_uncore_sanitize(struct drm_device *dev)
intel_disable_gt_powersave(dev);
}
+static void __intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
+{
+ struct intel_uncore_forcewake_domain *domain;
+ enum forcewake_domain_id id;
+
+ if (!dev_priv->uncore.funcs.force_wake_get)
+ return;
+
+ fw_domains &= dev_priv->uncore.fw_domains;
+
+ for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+ if (domain->wake_count++)
+ fw_domains &= ~(1 << id);
+ }
+
+ if (fw_domains)
+ dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
+}
+
/**
* intel_uncore_forcewake_get - grab forcewake domain references
* @dev_priv: i915 device instance
@@ -400,41 +419,39 @@ void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
enum forcewake_domains fw_domains)
{
unsigned long irqflags;
- struct intel_uncore_forcewake_domain *domain;
- enum forcewake_domain_id id;
if (!dev_priv->uncore.funcs.force_wake_get)
return;
WARN_ON(dev_priv->pm.suspended);
- fw_domains &= dev_priv->uncore.fw_domains;
-
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
- if (domain->wake_count++)
- fw_domains &= ~(1 << id);
- }
-
- if (fw_domains)
- dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
-
+ __intel_uncore_forcewake_get(dev_priv, fw_domains);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
/**
- * intel_uncore_forcewake_put - release a forcewake domain reference
+ * intel_uncore_forcewake_get__locked - grab forcewake domain references
* @dev_priv: i915 device instance
- * @fw_domains: forcewake domains to put references
+ * @fw_domains: forcewake domains to get reference on
*
- * This function drops the device-level forcewakes for specified
- * domains obtained by intel_uncore_forcewake_get().
+ * See intel_uncore_forcewake_get(). This variant places the onus
+ * on the caller to explicitly handle the dev_priv->uncore.lock spinlock.
*/
-void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
- enum forcewake_domains fw_domains)
+void intel_uncore_forcewake_get__locked(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
+{
+ assert_spin_locked(&dev_priv->uncore.lock);
+
+ if (!dev_priv->uncore.funcs.force_wake_get)
+ return;
+
+ __intel_uncore_forcewake_get(dev_priv, fw_domains);
+}
+
+static void __intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
{
- unsigned long irqflags;
struct intel_uncore_forcewake_domain *domain;
enum forcewake_domain_id id;
@@ -443,8 +460,6 @@ void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
fw_domains &= dev_priv->uncore.fw_domains;
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
if (WARN_ON(domain->wake_count == 0))
continue;
@@ -455,10 +470,48 @@ void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
domain->wake_count++;
fw_domain_arm_timer(domain);
}
+}
+
+/**
+ * intel_uncore_forcewake_put - release a forcewake domain reference
+ * @dev_priv: i915 device instance
+ * @fw_domains: forcewake domains to put references
+ *
+ * This function drops the device-level forcewakes for specified
+ * domains obtained by intel_uncore_forcewake_get().
+ */
+void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
+{
+ unsigned long irqflags;
+
+ if (!dev_priv->uncore.funcs.force_wake_put)
+ return;
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ __intel_uncore_forcewake_put(dev_priv, fw_domains);
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
+/**
+ * intel_uncore_forcewake_put__locked - grab forcewake domain references
+ * @dev_priv: i915 device instance
+ * @fw_domains: forcewake domains to get reference on
+ *
+ * See intel_uncore_forcewake_put(). This variant places the onus
+ * on the caller to explicitly handle the dev_priv->uncore.lock spinlock.
+ */
+void intel_uncore_forcewake_put__locked(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
+{
+ assert_spin_locked(&dev_priv->uncore.lock);
+
+ if (!dev_priv->uncore.funcs.force_wake_put)
+ return;
+
+ __intel_uncore_forcewake_put(dev_priv, fw_domains);
+}
+
void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
{
struct intel_uncore_forcewake_domain *domain;
@@ -472,7 +525,7 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
}
/* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+#define NEEDS_FORCE_WAKE(reg) \
((reg) < 0x40000 && (reg) != FORCEWAKE)
#define REG_RANGE(reg, start, end) ((reg) >= (start) && (reg) < (end))
@@ -674,7 +727,7 @@ static u##x \
gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
GEN6_READ_HEADER(x); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
- if (NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+ if (NEEDS_FORCE_WAKE(reg)) \
__force_wake_get(dev_priv, FORCEWAKE_RENDER); \
val = __raw_i915_read##x(dev_priv, reg); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
@@ -708,7 +761,7 @@ chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
GEN6_READ_FOOTER; \
}
-#define SKL_NEEDS_FORCE_WAKE(dev_priv, reg) \
+#define SKL_NEEDS_FORCE_WAKE(reg) \
((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg))
#define __gen9_read(x) \
@@ -716,9 +769,10 @@ static u##x \
gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
enum forcewake_domains fw_engine; \
GEN6_READ_HEADER(x); \
- if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+ hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
+ if (!SKL_NEEDS_FORCE_WAKE(reg)) \
fw_engine = 0; \
- else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+ else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
fw_engine = FORCEWAKE_RENDER; \
else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
fw_engine = FORCEWAKE_MEDIA; \
@@ -729,6 +783,7 @@ gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
if (fw_engine) \
__force_wake_get(dev_priv, fw_engine); \
val = __raw_i915_read##x(dev_priv, reg); \
+ hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
GEN6_READ_FOOTER; \
}
@@ -813,7 +868,7 @@ static void \
gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
GEN6_WRITE_HEADER; \
- if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+ if (NEEDS_FORCE_WAKE(reg)) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
__raw_i915_write##x(dev_priv, reg, val); \
@@ -828,7 +883,7 @@ static void \
hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
GEN6_WRITE_HEADER; \
- if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+ if (NEEDS_FORCE_WAKE(reg)) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
@@ -929,7 +984,8 @@ gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
bool trace) { \
enum forcewake_domains fw_engine; \
GEN6_WRITE_HEADER; \
- if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)) || \
+ hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
+ if (!SKL_NEEDS_FORCE_WAKE(reg) || \
is_gen9_shadowed(dev_priv, reg)) \
fw_engine = 0; \
else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
@@ -943,6 +999,8 @@ gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
if (fw_engine) \
__force_wake_get(dev_priv, fw_engine); \
__raw_i915_write##x(dev_priv, reg, val); \
+ hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
+ hsw_unclaimed_reg_detect(dev_priv); \
GEN6_WRITE_FOOTER; \
}
@@ -1144,8 +1202,6 @@ void intel_uncore_init(struct drm_device *dev)
switch (INTEL_INFO(dev)->gen) {
default:
- MISSING_CASE(INTEL_INFO(dev)->gen);
- return;
case 9:
ASSIGN_WRITE_MMIO_VFUNCS(gen9);
ASSIGN_READ_MMIO_VFUNCS(gen9);
@@ -1373,21 +1429,21 @@ static int ironlake_do_reset(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+ I915_WRITE(ILK_GDSR,
ILK_GRDOM_RENDER | ILK_GRDOM_RESET_ENABLE);
- ret = wait_for((I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) &
+ ret = wait_for((I915_READ(ILK_GDSR) &
ILK_GRDOM_RESET_ENABLE) == 0, 500);
if (ret)
return ret;
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+ I915_WRITE(ILK_GDSR,
ILK_GRDOM_MEDIA | ILK_GRDOM_RESET_ENABLE);
- ret = wait_for((I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) &
+ ret = wait_for((I915_READ(ILK_GDSR) &
ILK_GRDOM_RESET_ENABLE) == 0, 500);
if (ret)
return ret;
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, 0);
+ I915_WRITE(ILK_GDSR, 0);
return 0;
}
@@ -1413,20 +1469,89 @@ static int gen6_do_reset(struct drm_device *dev)
return ret;
}
-int intel_gpu_reset(struct drm_device *dev)
+static int wait_for_register(struct drm_i915_private *dev_priv,
+ const u32 reg,
+ const u32 mask,
+ const u32 value,
+ const unsigned long timeout_ms)
{
- if (INTEL_INFO(dev)->gen >= 6)
- return gen6_do_reset(dev);
+ return wait_for((I915_READ(reg) & mask) == value, timeout_ms);
+}
+
+static int gen8_do_reset(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_engine_cs *engine;
+ int i;
+
+ for_each_ring(engine, dev_priv, i) {
+ I915_WRITE(RING_RESET_CTL(engine->mmio_base),
+ _MASKED_BIT_ENABLE(RESET_CTL_REQUEST_RESET));
+
+ if (wait_for_register(dev_priv,
+ RING_RESET_CTL(engine->mmio_base),
+ RESET_CTL_READY_TO_RESET,
+ RESET_CTL_READY_TO_RESET,
+ 700)) {
+ DRM_ERROR("%s: reset request timeout\n", engine->name);
+ goto not_ready;
+ }
+ }
+
+ return gen6_do_reset(dev);
+
+not_ready:
+ for_each_ring(engine, dev_priv, i)
+ I915_WRITE(RING_RESET_CTL(engine->mmio_base),
+ _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET));
+
+ return -EIO;
+}
+
+static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *)
+{
+ if (!i915.reset)
+ return NULL;
+
+ if (INTEL_INFO(dev)->gen >= 8)
+ return gen8_do_reset;
+ else if (INTEL_INFO(dev)->gen >= 6)
+ return gen6_do_reset;
else if (IS_GEN5(dev))
- return ironlake_do_reset(dev);
+ return ironlake_do_reset;
else if (IS_G4X(dev))
- return g4x_do_reset(dev);
+ return g4x_do_reset;
else if (IS_G33(dev))
- return g33_do_reset(dev);
+ return g33_do_reset;
else if (INTEL_INFO(dev)->gen >= 3)
- return i915_do_reset(dev);
+ return i915_do_reset;
else
+ return NULL;
+}
+
+int intel_gpu_reset(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ int (*reset)(struct drm_device *);
+ int ret;
+
+ reset = intel_get_gpu_reset(dev);
+ if (reset == NULL)
return -ENODEV;
+
+ /* If the power well sleeps during the reset, the reset
+ * request may be dropped and never completes (causing -EIO).
+ */
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+ ret = reset(dev);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+
+ return ret;
+}
+
+bool intel_has_gpu_reset(struct drm_device *dev)
+{
+ return intel_get_gpu_reset(dev) != NULL;
}
void intel_uncore_check_errors(struct drm_device *dev)