From patchwork Mon Apr 18 10:15:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Gordon X-Patchwork-Id: 8869521 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 8FF8FBF29F for ; Mon, 18 Apr 2016 10:15:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5EAF02017D for ; Mon, 18 Apr 2016 10:15:23 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 32633201DD for ; Mon, 18 Apr 2016 10:15:22 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 8C21C6E57D; Mon, 18 Apr 2016 10:15:19 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTPS id 5D6EB6E579 for ; Mon, 18 Apr 2016 10:15:17 +0000 (UTC) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga101.fm.intel.com with ESMTP; 18 Apr 2016 03:15:17 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.24,501,1455004800"; d="scan'208";a="787077260" Received: from dsgordon-linux2.isw.intel.com ([10.102.226.88]) by orsmga003.jf.intel.com with ESMTP; 18 Apr 2016 03:15:14 -0700 From: Dave Gordon To: intel-gfx@lists.freedesktop.org Date: Mon, 18 Apr 2016 11:15:07 +0100 Message-Id: <1460974509-22616-1-git-send-email-david.s.gordon@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <5710D3AF.3000004@linux.intel.com> References: <5710D3AF.3000004@linux.intel.com> Organization: Intel Corporation (UK) Ltd. - Co. Reg. #1134945 - Pipers Way, Swindon SN3 1RJ Subject: [Intel-gfx] [PATCH v2 1/3] drm/i915/guc: keep GuC objects mapped in kernel 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=-5.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, 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 With the new i915_gem_obj_pin_map() interface, it makes sense to keep GuC objects (which are always pinned in memory and in the GGTT anyway) mapped into kernel address space, rather than mapping and unmapping them on each access. This preliminary patch sets up the pin-and-map for all GuC-specific objects, and updates the various setup/shutdown functions to use these long-term mappings rather than doing their own kmap_atomic() calls. v2: Invent & use accessor function i915_object_mapped_address() rather than accessing obj->mapping directly (Tvrtko Ursulin) Use IS_ERR() rather than checking for NULL (Tvrtko Ursulin) Added big comment about struct i915_guc_client & usage of the GEM object that it describes Cc: Signed-off-by: Alex Dai Signed-off-by: Dave Gordon --- drivers/gpu/drm/i915/i915_drv.h | 12 ++++++++++ drivers/gpu/drm/i915/i915_guc_submission.c | 38 +++++++++++------------------- drivers/gpu/drm/i915/intel_guc.h | 24 +++++++++++++++++++ 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 85102ad..439f149 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3025,6 +3025,18 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj); /** + * i915_object_mapped_address - address at which a GEM object is mapped + * @obj - the object (presumably already mapped into kernel address space) + * + * Returns the address at which an object has been mapped by a call to + * i915_gem_object_pin_map() above, or NULL if not currently mapped and pinned + */ +static inline void *i915_object_mapped_address(struct drm_i915_gem_object *obj) +{ + return obj->pages_pin_count == 0 ? NULL : obj->mapping; +} + +/** * i915_gem_object_unpin_map - releases an earlier mapping * @obj - the object to unmap * diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index da86bdb..de96306 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -179,15 +179,11 @@ static void guc_init_doorbell(struct intel_guc *guc, struct i915_guc_client *client) { struct guc_doorbell_info *doorbell; - void *base; - base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0)); - doorbell = base + client->doorbell_offset; + doorbell = client->client_base + client->doorbell_offset; - doorbell->db_status = 1; + doorbell->db_status = GUC_DOORBELL_ENABLED; doorbell->cookie = 0; - - kunmap_atomic(base); } static int guc_ring_doorbell(struct i915_guc_client *gc) @@ -256,16 +252,12 @@ static void guc_disable_doorbell(struct intel_guc *guc, { struct drm_i915_private *dev_priv = guc_to_i915(guc); struct guc_doorbell_info *doorbell; - void *base; i915_reg_t drbreg = GEN8_DRBREGL(client->doorbell_id); int value; - base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0)); - doorbell = base + client->doorbell_offset; - - doorbell->db_status = 0; + doorbell = client->client_base + client->doorbell_offset; - kunmap_atomic(base); + doorbell->db_status = GUC_DOORBELL_DISABLED; I915_WRITE(drbreg, I915_READ(drbreg) & ~GEN8_DRB_VALID); @@ -341,10 +333,8 @@ static void guc_init_proc_desc(struct intel_guc *guc, struct i915_guc_client *client) { struct guc_process_desc *desc; - void *base; - base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0)); - desc = base + client->proc_desc_offset; + desc = client->client_base + client->proc_desc_offset; memset(desc, 0, sizeof(*desc)); @@ -361,8 +351,6 @@ static void guc_init_proc_desc(struct intel_guc *guc, desc->wq_size_bytes = client->wq_size; desc->wq_status = WQ_STATUS_ACTIVE; desc->priority = client->priority; - - kunmap_atomic(base); } /* @@ -607,6 +595,7 @@ int i915_guc_submit(struct i915_guc_client *client, * This is a wrapper to create a gem obj. In order to use it inside GuC, the * object needs to be pinned lifetime. Also we must pin it to gtt space other * than [0, GUC_WOPCM_TOP) because this range is reserved inside GuC. + * The object is also pinned & mapped into kernel address space. * * Return: A drm_i915_gem_object if successful, otherwise NULL. */ @@ -620,13 +609,14 @@ static struct drm_i915_gem_object *gem_allocate_guc_obj(struct drm_device *dev, if (!obj) return NULL; - if (i915_gem_object_get_pages(obj)) { + if (IS_ERR(i915_gem_object_pin_map(obj))) { drm_gem_object_unreference(&obj->base); return NULL; } if (i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_OFFSET_BIAS | GUC_WOPCM_TOP)) { + i915_gem_object_unpin_map(obj); drm_gem_object_unreference(&obj->base); return NULL; } @@ -649,6 +639,9 @@ static void gem_release_guc_obj(struct drm_i915_gem_object *obj) if (i915_gem_obj_is_pinned(obj)) i915_gem_object_ggtt_unpin(obj); + if (i915_object_mapped_address(obj)) + i915_gem_object_unpin_map(obj); + drm_gem_object_unreference(&obj->base); } @@ -729,6 +722,8 @@ static struct i915_guc_client *guc_client_alloc(struct drm_device *dev, goto err; client->client_obj = obj; + client->client_base = i915_object_mapped_address(obj); + WARN_ON(!client->client_base); client->wq_offset = GUC_DB_SIZE; client->wq_size = GUC_WQ_SIZE; @@ -841,7 +836,6 @@ static void guc_create_ads(struct intel_guc *guc) struct guc_policies *policies; struct guc_mmio_reg_state *reg_state; struct intel_engine_cs *engine; - struct page *page; u32 size; /* The ads obj includes the struct itself and buffers passed to GuC */ @@ -857,9 +851,7 @@ static void guc_create_ads(struct intel_guc *guc) guc->ads_obj = obj; } - - page = i915_gem_object_get_page(obj, 0); - ads = kmap(page); + ads = i915_object_mapped_address(obj); /* * The GuC requires a "Golden Context" when it reinitialises @@ -897,8 +889,6 @@ static void guc_create_ads(struct intel_guc *guc) ads->reg_state_buffer = ads->reg_state_addr + sizeof(struct guc_mmio_reg_state); - - kunmap(page); } /* diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 3bb85b1..f2c051e 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -29,8 +29,31 @@ struct drm_i915_gem_request; +/* + * This structure primarily describes the GEM object shared with the GuC. + * The GEM object is held for the entire lifetime of our interaction with + * the GuC, being allocated before the GuC is loaded with its firmware. + * Because there's no way to update the address used by the GuC after + * initialisation, the shared object must stay pinned into the GGTT as + * long as the GuC is in use. We also keep it mapped into kernel address + * space, as it includes shared data that must be updated on every request + * submission. + * + * The single GEM object described here is actually made up of several + * separate areas, as far as the GuC is concerned. The first page includes + * the "process decriptor" which holds sequence data for the doorbell, and + * one cacheline which actually *is* the doorbell; a write to this will + * "ring" the doorbell (i.e. send an interrupt to the GuC). The subsequent + * pages of the client object constitute the work queue (a circular array + * of work items), again described in the process descriptor. + * + * Finally, we also keep a few statistics here, including the number of + * submissions to each engine, and a record of the last submission failure + * (if any). + */ struct i915_guc_client { struct drm_i915_gem_object *client_obj; + void *client_base; /* Mapped address of above */ struct intel_context *owner; struct intel_guc *guc; uint32_t priority; @@ -52,6 +75,7 @@ struct i915_guc_client { uint32_t q_fail; uint32_t b_fail; int retcode; + int spare; /* pad to 32 DWords */ }; enum intel_guc_fw_status {