From patchwork Fri Aug 4 16:27:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Wajdeczko X-Patchwork-Id: 9881665 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8E7D5602B8 for ; Fri, 4 Aug 2017 16:27:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A2D7284B5 for ; Fri, 4 Aug 2017 16:27:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6CE422891B; Fri, 4 Aug 2017 16:27:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DAD31284B5 for ; Fri, 4 Aug 2017 16:27:57 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 62D356E4EC; Fri, 4 Aug 2017 16:27:41 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by gabe.freedesktop.org (Postfix) with ESMTPS id C0AF66E4E6 for ; Fri, 4 Aug 2017 16:27:39 +0000 (UTC) Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga105.fm.intel.com with ESMTP; 04 Aug 2017 09:27:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.41,321,1498546800"; d="scan'208";a="115684119" Received: from irvmail001.ir.intel.com ([163.33.26.43]) by orsmga004.jf.intel.com with ESMTP; 04 Aug 2017 09:27:37 -0700 Received: from mwajdecz-MOBL1.ger.corp.intel.com (mwajdecz-mobl1.ger.corp.intel.com [172.28.174.25]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id v74GRMdU010586; Fri, 4 Aug 2017 17:27:36 +0100 From: Michal Wajdeczko To: intel-gfx@lists.freedesktop.org Date: Fri, 4 Aug 2017 16:27:08 +0000 Message-Id: <20170804162712.20468-12-michal.wajdeczko@intel.com> X-Mailer: git-send-email 2.10.1.windows.1 In-Reply-To: <20170804162712.20468-1-michal.wajdeczko@intel.com> References: <20170804162712.20468-1-michal.wajdeczko@intel.com> Subject: [Intel-gfx] [PATCH 11/15] drm/i915/guc: Implement response handling in send_ct() 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-Virus-Scanned: ClamAV using ClamSMTP GuC may return not only small data encoded in the status dword, but can also append additional data into the response message. We will copy this extra data into provided buffer, and use number of received data dwords as new success return value. Signed-off-by: Michal Wajdeczko Cc: Oscar Mateo Cc: Michel Thierry Cc: Daniele Ceraolo Spurio --- drivers/gpu/drm/i915/intel_guc_ct.c | 120 +++++++++++++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_guc_ct.h | 5 ++ 2 files changed, 115 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_guc_ct.c b/drivers/gpu/drm/i915/intel_guc_ct.c index 4fabea17..4dfa0b9 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/intel_guc_ct.c @@ -24,6 +24,14 @@ #include "i915_drv.h" #include "intel_guc_ct.h" +struct ct_request { + struct list_head link; + u32 fence; + u32 status; + u32 response_len; + u32 *response_buf; +}; + enum { CTB_SEND = 0, CTB_RECV = 1 }; enum { CTB_OWNER_HOST = 0 }; @@ -32,6 +40,9 @@ void intel_guc_ct_init_early(struct intel_guc_ct *ct) { /* we're using static channel owners */ ct->host_channel.owner = CTB_OWNER_HOST; + + spin_lock_init(&ct->lock); + INIT_LIST_HEAD(&ct->pending_requests); } static inline const char *guc_ct_buffer_type_to_str(u32 type) @@ -265,7 +276,8 @@ static u32 ctch_get_next_fence(struct intel_guc_ct_channel *ctch) static int ctb_write(struct intel_guc_ct_buffer *ctb, const u32 *action, u32 len /* in dwords */, - u32 fence) + u32 fence, + bool send_response) { struct guc_ct_buffer_desc *desc = ctb->desc; u32 head = desc->head / 4; /* in dwords */ @@ -301,6 +313,7 @@ static int ctb_write(struct intel_guc_ct_buffer *ctb, */ header = (len << GUC_CT_MSG_LEN_SHIFT) | (GUC_CT_MSG_WRITE_FENCE_TO_DESC) | + (send_response ? GUC_CT_MSG_SEND_STATUS : 0) | (action[0] << GUC_CT_MSG_ACTION_SHIFT); cmds[tail] = header; @@ -364,14 +377,48 @@ static int wait_for_desc_update(struct guc_ct_buffer_desc *desc, return err; } +/* Wait for the Guc response. + * We will update request status from the response message handler. + * + * @req: pointer to pending request + * @status: placeholder for status + * return: 0 response received (status is valid) + * -ETIMEDOUT no response within hardcoded timeout + * \see guc_handle_response() + */ +static int wait_for_response_msg(struct ct_request *req, u32 *status) +{ + int err; + + /* + * Fast commands should complete in less than 10us, so sample quickly + * up to that length of time, then switch to a slower sleep-wait loop. + * No GuC command should ever take longer than 10ms. + */ +#define done INTEL_GUC_RECV_IS_RESPONSE(READ_ONCE(req->status)) + err = wait_for_us(done, 10); + if (err) + err = wait_for(done, 1000); +#undef done + + if (unlikely(err)) + DRM_ERROR("CT: fence %u err %d\n", req->fence, err); + + *status = req->status; + return err; +} + static int ctch_send(struct intel_guc *guc, struct intel_guc_ct_channel *ctch, const u32 *action, u32 len, - u32 *status) + u32 *status, + u32 *response) { struct intel_guc_ct_buffer *ctb = &ctch->ctbs[CTB_SEND]; struct guc_ct_buffer_desc *desc = ctb->desc; + struct ct_request request; + unsigned long flags; u32 fence; int err; @@ -380,18 +427,48 @@ static int ctch_send(struct intel_guc *guc, GEM_BUG_ON(len & ~GUC_CT_MSG_LEN_MASK); fence = ctch_get_next_fence(ctch); - err = ctb_write(ctb, action, len, fence); + request.fence = fence; + request.status = 0; + request.response_len = 0; + request.response_buf = response; + + spin_lock_irqsave(&guc->ct.lock, flags); + list_add_tail(&request.link, &guc->ct.pending_requests); + spin_unlock_irqrestore(&guc->ct.lock, flags); + + err = ctb_write(ctb, action, len, fence, !!response); if (unlikely(err)) - return err; + goto unlink; intel_guc_notify(guc); - err = wait_for_desc_update(desc, fence, status); + if (response) + err = wait_for_response_msg(&request, status); + else + err = wait_for_desc_update(desc, fence, status); if (unlikely(err)) - return err; - if (INTEL_GUC_RECV_TO_STATUS(*status) != INTEL_GUC_STATUS_SUCCESS) - return -EIO; - return INTEL_GUC_RECV_TO_DATA(*status); + goto unlink; + + if (INTEL_GUC_RECV_TO_STATUS(*status) != INTEL_GUC_STATUS_SUCCESS) { + err = -EIO; + goto unlink; + } + + if (response) { + /* If response is expected, there shall be no data in the status */ + WARN_ON(INTEL_GUC_RECV_TO_DATA(request.status)); + err = request.response_len; + } else { + /* If response is not expected, return data from the status */ + err = INTEL_GUC_RECV_TO_DATA(*status); + } + +unlink: + spin_lock_irqsave(&guc->ct.lock, flags); + list_del(&request.link); + spin_unlock_irqrestore(&guc->ct.lock, flags); + + return err; } /* @@ -406,7 +483,7 @@ static int intel_guc_send_ct(struct intel_guc *guc, const u32 *action, u32 len, mutex_lock(&guc->send_mutex); - ret = ctch_send(guc, ctch, action, len, &status); + ret = ctch_send(guc, ctch, action, len, &status, response); if (unlikely(ret < 0)) { DRM_ERROR("CT: send action %#X failed; err=%d status=%#X\n", action[0], ret, status); @@ -485,7 +562,12 @@ static int ctb_read(struct intel_guc_ct_buffer *ctb, u32 *data) static int guc_handle_response(struct intel_guc *guc, const u32 *data) { u32 header = data[0]; + u32 fence = data[1]; + u32 status = data[2]; u32 len = ct_header_get_len(header) + 1; /* total len with header */ + struct ct_request *req; + bool found = false; + unsigned long flags; GEM_BUG_ON(!ct_header_is_response(header)); /* beyond header, data shall at least include fence and status */ @@ -494,6 +576,24 @@ static int guc_handle_response(struct intel_guc *guc, const u32 *data) return -EPROTO; } + spin_lock_irqsave(&guc->ct.lock, flags); + list_for_each_entry(req, &guc->ct.pending_requests, link) { + if (req->fence != fence) { + DRM_DEBUG_DRIVER("CT: request %u awaits response\n", + req->fence); + continue; + } + req->response_len = len - 3; + if (req->response_buf) + memcpy(req->response_buf, data + 3, 4*req->response_len); + WRITE_ONCE(req->status, status); + found = true; + break; + } + spin_unlock_irqrestore(&guc->ct.lock, flags); + + if (!found) + DRM_ERROR("CT: unsolicited response %*phn\n", 4*len, data); return 0; } diff --git a/drivers/gpu/drm/i915/intel_guc_ct.h b/drivers/gpu/drm/i915/intel_guc_ct.h index 6d97f36..557c1e8 100644 --- a/drivers/gpu/drm/i915/intel_guc_ct.h +++ b/drivers/gpu/drm/i915/intel_guc_ct.h @@ -71,10 +71,15 @@ struct intel_guc_ct_channel { /** Holds all command transport channels. * * @host_channel: main channel used by the host + * @lock: spin lock for pending requests list + * @pending_requests: list of pending requests */ struct intel_guc_ct { struct intel_guc_ct_channel host_channel; /* other channels are tbd */ + + spinlock_t lock; + struct list_head pending_requests; }; void intel_guc_ct_init_early(struct intel_guc_ct *ct);