From patchwork Wed Apr 29 22:13:34 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: yu.dai@intel.com X-Patchwork-Id: 6298691 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9AF44BEEED for ; Wed, 29 Apr 2015 22:15:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 606CE201B9 for ; Wed, 29 Apr 2015 22:15:20 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 386FF2017D for ; Wed, 29 Apr 2015 22:15:19 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B7E896E73A; Wed, 29 Apr 2015 15:15:18 -0700 (PDT) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by gabe.freedesktop.org (Postfix) with ESMTP id 1018B6E731 for ; Wed, 29 Apr 2015 15:15:17 -0700 (PDT) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga103.jf.intel.com with ESMTP; 29 Apr 2015 15:15:16 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,672,1422950400"; d="scan'208";a="721303762" Received: from alex-hsw.fm.intel.com ([10.19.123.33]) by orsmga002.jf.intel.com with ESMTP; 29 Apr 2015 15:15:17 -0700 From: yu.dai@intel.com To: intel-gfx@lists.freedesktop.org Date: Wed, 29 Apr 2015 15:13:34 -0700 Message-Id: <1430345615-5576-14-git-send-email-yu.dai@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1430345615-5576-1-git-send-email-yu.dai@intel.com> References: <1430345615-5576-1-git-send-email-yu.dai@intel.com> Subject: [Intel-gfx] [PATCH v6 13/14] drm/i915: Enable GuC firmware log X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Alex Dai Allocate a gem obj to hold GuC log data. Also a debugfs interface (i915_guc_log_dump) is provided to print out the log content. Issue: VIZ-4884 Signed-off-by: Alex Dai --- drivers/gpu/drm/i915/i915_debugfs.c | 41 +++++++++++++++++---- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_params.c | 5 +++ drivers/gpu/drm/i915/intel_guc.h | 1 + drivers/gpu/drm/i915/intel_guc_loader.c | 64 ++++++++++++++++++++++++++++++++- 5 files changed, 104 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index f12bbee..f47714c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2332,14 +2332,14 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data) tmp = I915_READ(GUC_STATUS); - seq_puts(m, "\nResponse from GuC:\n"); + seq_printf(m, "\nGuC status 0x%08x:\n", tmp); seq_printf(m, "\tBootrom status = 0x%x\n", (tmp & GS_BOOTROM_MASK) >> GS_BOOTROM_SHIFT); seq_printf(m, "\tuKernel status = 0x%x\n", (tmp & GS_UKERNEL_MASK) >> GS_UKERNEL_SHIFT); seq_printf(m, "\tMIA Core status = 0x%x\n", (tmp & GS_MIA_MASK) >> GS_MIA_SHIFT); - seq_puts(m, "Scratch registers value:\n"); + seq_puts(m, "\nScratch registers value:\n"); for (i = 0; i < 16; i++) seq_printf(m, "\t%2d: \t0x%x\n", i, I915_READ(SOFT_SCRATCH(i))); @@ -2352,13 +2352,11 @@ static int i915_guc_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_guc guc; - struct i915_guc_client client; + struct i915_guc_client client = { 0 }; - if (!i915.enable_guc_scheduling) + if (!HAS_GUC_SCHED(dev_priv->dev)) return 0; - memset(&client, 0, sizeof(struct i915_guc_client)); - /* Take a local copy of the GuC data, so we can dump it at leisure */ spin_lock(&dev_priv->guc.host2guc_lock); guc = dev_priv->guc; @@ -2376,7 +2374,7 @@ static int i915_guc_info(struct seq_file *m, void *data) seq_printf(m, "GuC action failure count: %u\n", guc.action_fail); seq_printf(m, "GuC last action error code: %d\n", guc.action_err); - seq_printf(m, "GuC execbuf client @ %p:\n", guc.execbuf_client); + seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client); seq_printf(m, "\tTotal submissions: %llu\n", client.submissions); seq_printf(m, "\tFailed to queue: %u\n", client.q_fail); seq_printf(m, "\tFailed doorbell: %u\n", client.b_fail); @@ -2387,6 +2385,34 @@ static int i915_guc_info(struct seq_file *m, void *data) return 0; } +static int i915_guc_log_dump(struct seq_file *m, void *data) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *log_obj = dev_priv->guc.log_obj; + u32 *log; + int i = 0, pg; + + if (!log_obj) + return 0; + + for (pg = 0; pg < log_obj->base.size / PAGE_SIZE; pg++) { + log = kmap_atomic(i915_gem_object_get_page(log_obj, pg)); + + for (i = 0; i < PAGE_SIZE / sizeof(u32); i += 4) + seq_printf(m, "0x%08x 0x%08x 0x%08x 0x%08x\n", + *(log + i), *(log + i + 1), + *(log + i + 2), *(log + i + 3)); + + kunmap_atomic(log); + } + + seq_putc(m, '\n'); + + return 0; +} + static int i915_edp_psr_status(struct seq_file *m, void *data) { struct drm_info_node *node = m->private; @@ -4855,6 +4881,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_gem_batch_pool", i915_gem_batch_pool_info, 0}, {"i915_guc_info", i915_guc_info, 0}, {"i915_guc_load_status", i915_guc_load_status_info, 0}, + {"i915_guc_log_dump", i915_guc_log_dump, 0}, {"i915_frequency_info", i915_frequency_info, 0}, {"i915_hangcheck_info", i915_hangcheck_info, 0}, {"i915_drpc_info", i915_drpc_info, 0}, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0d60119..aa3d81b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2505,6 +2505,7 @@ struct i915_params { bool disable_display; bool disable_vtd_wa; bool enable_guc_scheduling; + unsigned int guc_log_level; int use_mmio_flip; int mmio_debug; bool verbose_state_checks; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 9ad2e27..95e4eb7 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -54,6 +54,7 @@ struct i915_params i915 __read_mostly = { .verbose_state_checks = 1, .nuclear_pageflip = 0, .enable_guc_scheduling = false, + .guc_log_level = 0, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -188,3 +189,7 @@ MODULE_PARM_DESC(nuclear_pageflip, module_param_named(enable_guc_scheduling, i915.enable_guc_scheduling, bool, 0400); MODULE_PARM_DESC(enable_guc_scheduling, "Enable GuC scheduling (default:false)"); + +module_param_named(guc_log_level, i915.guc_log_level, int, 0400); +MODULE_PARM_DESC(guc_log_level, + "GuC firmware logging level (0:disabled, 1~4:enabled)"); diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index b096d1a..3673511 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -66,6 +66,7 @@ struct intel_guc { spinlock_t host2guc_lock; struct drm_i915_gem_object *ctx_pool_obj; + struct drm_i915_gem_object *log_obj; struct i915_guc_client *execbuf_client; diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index eb25cfb..a61d1df 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -51,6 +51,12 @@ * 512K. In order to exclude 0-512K address space from GGTT, all gfx objects * used by GuC is pinned with PIN_OFFSET_BIAS along with size of WOPCM. * + * Firmware log: + * Firmware log is enabled by setting i915.guc_log_level to non-negative level. + * Log data is printed out via reading debugfs i915_guc_log_dump. Reading from + * i915_guc_load_status will print out firmware loading status and scratch + * registers value. + * */ #define I915_SKL_GUC_UCODE "i915/skl_guc_ver1.bin" @@ -58,6 +64,10 @@ MODULE_FIRMWARE(I915_SKL_GUC_UCODE); #define I915_BXT_GUC_UCODE "i915/bxt_guc_ver1.bin" MODULE_FIRMWARE(I915_BXT_GUC_UCODE); +#define GUC_LOG_DPC_PAGES 3 +#define GUC_LOG_ISR_PAGES 3 +#define GUC_LOG_CRASH_PAGES 1 + /** * intel_guc_allocate_gem_obj() - Allocate gem object for GuC usage * @dev: drm device @@ -204,6 +214,51 @@ static u32 get_core_family(struct drm_device *dev) } } +static void create_guc_log(struct intel_guc *guc, u32 *params) +{ + struct drm_i915_private *dev_priv = + container_of(guc, struct drm_i915_private, guc); + struct drm_i915_gem_object *obj; + u32 flags, size; + + /* The first page is to save log buffer state. Allocate one + * extra page for others in case for overlap */ + size = (1 + GUC_LOG_DPC_PAGES + 1 + + GUC_LOG_ISR_PAGES + 1 + + GUC_LOG_CRASH_PAGES + 1) << PAGE_SHIFT; + + if (!guc->log_obj) { + obj = intel_guc_allocate_gem_obj(dev_priv->dev, size); + if (!obj) { + /* logging will be off */ + *(params + GUC_CTL_LOG_PARAMS) = 0; + i915.guc_log_level = 0; + return; + } + + guc->log_obj = obj; + } + else + obj = guc->log_obj; + + /* each allocated unit is a page */ + flags = GUC_LOG_VALID | GUC_LOG_NOTIFY_ON_HALF_FULL | + (GUC_LOG_DPC_PAGES << GUC_LOG_DPC_SHIFT) | + (GUC_LOG_ISR_PAGES << GUC_LOG_ISR_SHIFT) | + (GUC_LOG_CRASH_PAGES << GUC_LOG_CRASH_SHIFT); + + size = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT; /* in pages */ + flags |= size << GUC_LOG_BUF_ADDR_SHIFT; + + *(params + GUC_CTL_LOG_PARAMS) = flags; + + i915.guc_log_level--; + if (i915.guc_log_level > GUC_LOG_VERBOSITY_ULTRA) + i915.guc_log_level = GUC_LOG_VERBOSITY_ULTRA; + + *(params + GUC_CTL_DEBUG) |= i915.guc_log_level; +} + static void set_guc_init_params(struct drm_i915_private *dev_priv) { u32 params[GUC_CTL_MAX_DWORDS]; @@ -227,7 +282,9 @@ static void set_guc_init_params(struct drm_i915_private *dev_priv) params[GUC_CTL_FEATURE] |= GUC_CTL_DISABLE_SCHEDULER | GUC_CTL_VCS2_ENABLED; - /* XXX: Set up log buffer */ + /* Set up log buffer */ + if (i915.guc_log_level > 0) + create_guc_log(&dev_priv->guc, params); /* If GuC scheduling is enabled, setup params here. */ if (i915.enable_guc_scheduling) { @@ -476,6 +533,11 @@ void intel_guc_ucode_fini(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw; + if (dev_priv->guc.log_obj) { + intel_guc_release_gem_obj(dev_priv->guc.log_obj); + dev_priv->guc.log_obj = NULL; + } + guc_scheduler_fini(dev); intel_uc_fw_fini(guc_fw);