From patchwork Thu Apr 18 01:52:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Widawsky X-Patchwork-Id: 2457231 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id CEA863FD8C for ; Thu, 18 Apr 2013 02:21:00 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8B637E5DE8 for ; Wed, 17 Apr 2013 19:21:00 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from shiva.localdomain (unknown [209.20.75.48]) by gabe.freedesktop.org (Postfix) with ESMTP id 81E77E60F0 for ; Wed, 17 Apr 2013 18:50:13 -0700 (PDT) Received: by shiva.localdomain (Postfix, from userid 1005) id A11C488627; Thu, 18 Apr 2013 01:50:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on shiva.chad-versace.us X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00, URIBL_BLOCKED autolearn=unavailable version=3.3.2 Received: from lundgren.kumite (c-24-21-100-90.hsd1.or.comcast.net [24.21.100.90]) by shiva.localdomain (Postfix) with ESMTPSA id 776F988013; Thu, 18 Apr 2013 01:50:10 +0000 (UTC) From: Ben Widawsky To: intel-gfx@lists.freedesktop.org Date: Wed, 17 Apr 2013 18:52:31 -0700 Message-Id: <1366249951-5030-1-git-send-email-ben@bwidawsk.net> X-Mailer: git-send-email 1.8.2.1 Cc: Ben Widawsky Subject: [Intel-gfx] [PATCH] [RFC] drm/i915: Scratch page checker X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Errors-To: intel-gfx-bounces+patchwork-intel-gfx=patchwork.kernel.org@lists.freedesktop.org Periodically check the scratch page to see if it changes. Scratch page changes almost always indicate something is wrong. We never expect a non-zero filled page, so potentially we could directly put that md5 value for checking. I think the code as it is will be a bit more robust. Pretty RFC here since I've only compiled and run it for a few seconds. Recommended-by: Stephane Marchesin Signed-off-by: Ben Widawsky --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/i915/i915_drv.c | 5 +++ drivers/gpu/drm/i915/i915_drv.h | 14 +++++++ drivers/gpu/drm/i915/i915_gem_gtt.c | 73 +++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 19b8e0d..44efe74 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -125,6 +125,8 @@ config DRM_I915 depends on DRM depends on AGP depends on AGP_INTEL + select CRYPTO + select CRYPTO_MD5 # we need shmfs for the swappable backing store, and in particular # the shmem_readpage() which depends upon tmpfs select SHMEM diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9ebe895..a1f6142 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -128,6 +128,11 @@ 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)"); +int i915_enable_scratch_checker __read_mostly = 0; +module_param_named(enable_scratch_checker, i915_enable_scratch_checker, int, 0600); +MODULE_PARM_DESC(enable_scratch_checker, + "Enable periodic timer to find stray writes to the scratch page (default: false)"); + static struct drm_driver driver; extern int intel_agp_enabled; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d5dcf7f..c1f4ef7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -43,6 +43,8 @@ #include #include #include +#include +#include /* General customization: */ @@ -869,6 +871,16 @@ struct i915_gpu_error { unsigned int stop_rings; }; +struct i915_scratch_checker { + struct scatterlist sg; /* sg for scratch page */ + struct hash_desc hash; + char last_hash[MD5_DIGEST_SIZE]; + +#define I915_SCRATCH_DIRT_PERIOD 1000 /* in ms */ +#define I915_SCRATCH_DIRT_JIFFIES msecs_to_jiffies(I915_SCRATCH_DIRT_PERIOD) + struct timer_list timer; +}; + enum modeset_restore { MODESET_ON_LID_OPEN, MODESET_DONE, @@ -1058,6 +1070,7 @@ typedef struct drm_i915_private { struct drm_mm_node *compressed_llb; struct i915_gpu_error gpu_error; + struct i915_scratch_checker scratch_checker; /* list of fbdev register on this device */ struct intel_fbdev *fbdev; @@ -1435,6 +1448,7 @@ 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_enable_scratch_checker __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); extern int i915_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 50df194..df7a3a8 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -660,6 +660,72 @@ void i915_gem_init_global_gtt(struct drm_device *dev) i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size); } +static void scratch_checker(unsigned long data) +{ + struct drm_i915_private *dev_priv = (struct drm_i915_private *)data; + char hash[MD5_DIGEST_SIZE]; + int ret; + + ret = crypto_hash_digest(&dev_priv->scratch_checker.hash, + &dev_priv->scratch_checker.sg, PAGE_SIZE, + hash); + if (ret) { + DRM_DEBUG_DRIVER("Couldn't hash scratch\n"); + goto out; + } + + if (!memcmp(hash, dev_priv->scratch_checker.last_hash, MD5_DIGEST_SIZE)) + goto out; + + DRM_DEBUG("Scratch page contents changed\n"); + memcpy(dev_priv->scratch_checker.last_hash, hash, MD5_DIGEST_SIZE); + +out: + mod_timer(&dev_priv->scratch_checker.timer, + round_jiffies_up(jiffies + I915_SCRATCH_DIRT_JIFFIES)); +} + +static void scratch_checker_init(struct drm_i915_private *dev_priv) +{ + int ret; + + sg_init_table(&dev_priv->scratch_checker.sg, 1); + sg_set_page(&dev_priv->scratch_checker.sg, dev_priv->gtt.scratch_page, + 4096, 0); + + dev_priv->scratch_checker.hash.tfm = crypto_alloc_hash("md5", 0, + CRYPTO_ALG_ASYNC); + if (IS_ERR_OR_NULL(dev_priv->scratch_checker.hash.tfm)) + return; + + ret = crypto_hash_init(&dev_priv->scratch_checker.hash); + if (ret) + goto err; + + ret = crypto_hash_digest(&dev_priv->scratch_checker.hash, + &dev_priv->scratch_checker.sg, PAGE_SIZE, + dev_priv->scratch_checker.last_hash); + if (ret) + goto err; + + setup_timer(&dev_priv->scratch_checker.timer, scratch_checker, + (unsigned long) dev_priv); + return; + +err: + crypto_free_hash(dev_priv->scratch_checker.hash.tfm); + dev_priv->scratch_checker.hash.tfm = NULL; +} + +static void scratch_checker_fini(struct drm_i915_private *dev_priv) +{ + if (dev_priv->scratch_checker.hash.tfm) + return; + + del_timer_sync(&dev_priv->scratch_checker.timer); + crypto_free_hash(dev_priv->scratch_checker.hash.tfm); +} + static int setup_scratch_page(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -682,6 +748,7 @@ static int setup_scratch_page(struct drm_device *dev) #endif dev_priv->gtt.scratch_page = page; dev_priv->gtt.scratch_page_dma = dma_addr; + scratch_checker_init(dev_priv); return 0; } @@ -689,6 +756,7 @@ static int setup_scratch_page(struct drm_device *dev) static void teardown_scratch_page(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + scratch_checker_fini(dev_priv); set_pages_wb(dev_priv->gtt.scratch_page, 1); pci_unmap_page(dev->pdev, dev_priv->gtt.scratch_page_dma, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); @@ -811,6 +879,7 @@ static void i915_gmch_remove(struct drm_device *dev) intel_gmch_remove(); } + int i915_gem_gtt_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -840,5 +909,9 @@ int i915_gem_gtt_init(struct drm_device *dev) DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", dev_priv->gtt.stolen_size >> 20); + if (i915_enable_scratch_checker) + mod_timer(&dev_priv->scratch_checker.timer, + jiffies + I915_SCRATCH_DIRT_JIFFIES); + return 0; }