From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.7 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 29B99C3A59F for ; Thu, 29 Aug 2019 17:07:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D5A5A2166E for ; Thu, 29 Aug 2019 17:07:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="B+Ml0Sdp" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727173AbfH2RHY (ORCPT ); Thu, 29 Aug 2019 13:07:24 -0400 Received: from mail-pf1-f193.google.com ([209.85.210.193]:33445 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726893AbfH2RHY (ORCPT ); Thu, 29 Aug 2019 13:07:24 -0400 Received: by mail-pf1-f193.google.com with SMTP id g2so2503685pfq.0; Thu, 29 Aug 2019 10:07:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gzYY4eM1IPxC7lB77c02vRvvAN64KenUFpKc/ct/ToM=; b=B+Ml0SdptNNDfk8AfZddVib03vkpDQ6hAjis/DkPImXMs+D7WwnU9hVSQ8STkmYl+a FWJU+fWNc7VE5CPElMjxLpJ+u0mRjZ5jjlfbauNt9vvLUYv8gpYE9r5/m4QazITvpek0 NXejgXoDQS+/pFV1ZN+w6IVTPsGheYTXARQIPDDxgy81IaFyo6YUQXO9bLvS3A7JYL8C ZDe+afBUhIjNp5MlTtlW3EaU+mtLRGJuuI6lANfbUpNmqOKJVOr2hWJPhFkNOIKI74zK O8NRH1P90KLu+ImX2F5FqHnjSHn48VGJnHDq9HGQLtXt06oMlL2nQ8O6Gw6j/TMLjqlj KHPA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gzYY4eM1IPxC7lB77c02vRvvAN64KenUFpKc/ct/ToM=; b=aQnLpDKIEvJisXgBQvzaEcTemguibyIL07d9TQhpCPjG6yc0j5zcE5H/cb97ELR85q PvQcbMioBerUV40mKHuFs3+pFLo8X6rHvhPFtvBujThxmaselW50Q3Qe7g4Gxwp6I9Zx nTGgZCmJNBagwZyCQ5EZDExAFYOj5BsnsNTboDHJwh1pdqqNJWOr/yoe8rM/u5X6KOkT 6SY4SNp1qzTbjuTMA0maDNRa88ACqFwY4CIB6qFST9EJuoBzXFgQbljc69UIRPGW7gHm P4eCtauDWzrwBhP3JIyRbegzWw5o90gQ1Iolm/1td8ftobjLaoDM9xtKPkEfdgX+SaS1 7xkQ== X-Gm-Message-State: APjAAAVfQF8lxIYb05Txt0N+nLOUnKybOnXYc4PNjnqPvW4HAawy5kY0 DshOUw7KfIRaAp9kJCPySvo= X-Google-Smtp-Source: APXvYqzyon9oB41UJCoT6/V76r61iEPK0Hlo1gBsNvoMIec6OeAP8371RUBwC2yp0ufuDGUm6s8mCA== X-Received: by 2002:aa7:97aa:: with SMTP id d10mr12831562pfq.176.1567098443324; Thu, 29 Aug 2019 10:07:23 -0700 (PDT) Received: from localhost ([100.118.89.196]) by smtp.gmail.com with ESMTPSA id r12sm2527110pgb.73.2019.08.29.10.07.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Aug 2019 10:07:22 -0700 (PDT) From: Rob Clark To: dri-devel@lists.freedesktop.org Cc: Rob Clark , Rob Clark , Sean Paul , David Airlie , Daniel Vetter , linux-arm-msm@vger.kernel.org (open list:DRM DRIVER FOR MSM ADRENO GPU), freedreno@lists.freedesktop.org (open list:DRM DRIVER FOR MSM ADRENO GPU), linux-kernel@vger.kernel.org (open list) Subject: [PATCH 08/10] drm/msm: async commit support Date: Thu, 29 Aug 2019 09:45:16 -0700 Message-Id: <20190829164601.11615-9-robdclark@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190829164601.11615-1-robdclark@gmail.com> References: <20190829164601.11615-1-robdclark@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org From: Rob Clark Now that flush/wait/complete is decoupled from the "synchronous" part of atomic commit_tail(), add support to defer flush to a timer that expires shortly before vblank for async commits. In this way, multiple atomic commits (for example, cursor updates) can be coalesced into a single flush at the end of the frame. v2: don't hold lock over ->wait_flush(), to avoid locking interaction that was causing fps drop when combining page flips or non-async atomic commits and lots of legacy cursor updates Signed-off-by: Rob Clark --- drivers/gpu/drm/msm/msm_atomic.c | 156 ++++++++++++++++++++++++++++++- drivers/gpu/drm/msm/msm_drv.c | 1 + drivers/gpu/drm/msm/msm_drv.h | 4 + drivers/gpu/drm/msm/msm_kms.h | 50 ++++++++++ 4 files changed, 210 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 614fb9c5bb58..8f8f74337cb4 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -29,6 +29,95 @@ int msm_atomic_prepare_fb(struct drm_plane *plane, return msm_framebuffer_prepare(new_state->fb, kms->aspace); } +static void msm_atomic_async_commit(struct msm_kms *kms, int crtc_idx) +{ + unsigned crtc_mask = BIT(crtc_idx); + + mutex_lock(&kms->commit_lock); + + if (!(kms->pending_crtc_mask & crtc_mask)) { + mutex_unlock(&kms->commit_lock); + return; + } + + kms->pending_crtc_mask &= ~crtc_mask; + + kms->funcs->enable_commit(kms); + + /* + * Flush hardware updates: + */ + DRM_DEBUG_ATOMIC("triggering async commit\n"); + kms->funcs->flush_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + + /* + * Wait for flush to complete: + */ + kms->funcs->wait_flush(kms, crtc_mask); + + mutex_lock(&kms->commit_lock); + kms->funcs->complete_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + kms->funcs->disable_commit(kms); +} + +static enum hrtimer_restart msm_atomic_pending_timer(struct hrtimer *t) +{ + struct msm_pending_timer *timer = container_of(t, + struct msm_pending_timer, timer); + struct msm_drm_private *priv = timer->kms->dev->dev_private; + + queue_work(priv->wq, &timer->work); + + return HRTIMER_NORESTART; +} + +static void msm_atomic_pending_work(struct work_struct *work) +{ + struct msm_pending_timer *timer = container_of(work, + struct msm_pending_timer, work); + + msm_atomic_async_commit(timer->kms, timer->crtc_idx); +} + +void msm_atomic_init_pending_timer(struct msm_pending_timer *timer, + struct msm_kms *kms, int crtc_idx) +{ + timer->kms = kms; + timer->crtc_idx = crtc_idx; + hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + timer->timer.function = msm_atomic_pending_timer; + INIT_WORK(&timer->work, msm_atomic_pending_work); +} + +static bool can_do_async(struct drm_atomic_state *state, + struct drm_crtc **async_crtc) +{ + struct drm_connector_state *connector_state; + struct drm_connector *connector; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i, num_crtcs = 0; + + if (!(state->legacy_cursor_update || state->async_update)) + return false; + + /* any connector change, means slow path: */ + for_each_new_connector_in_state(state, connector, connector_state, i) + return false; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + if (drm_atomic_crtc_needs_modeset(crtc_state)) + return false; + if (++num_crtcs > 1) + return false; + *async_crtc = crtc; + } + + return true; +} + /* Get bitmask of crtcs that will need to be flushed. The bitmask * can be used with for_each_crtc_mask() iterator, to iterate * effected crtcs without needing to preserve the atomic state. @@ -50,9 +139,25 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) struct drm_device *dev = state->dev; struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; + struct drm_crtc *async_crtc = NULL; unsigned crtc_mask = get_crtc_mask(state); + bool async = kms->funcs->vsync_time && + can_do_async(state, &async_crtc); kms->funcs->enable_commit(kms); + + /* + * Ensure any previous (potentially async) commit has + * completed: + */ + kms->funcs->wait_flush(kms, crtc_mask); + + mutex_lock(&kms->commit_lock); + + /* + * Now that there is no in-progress flush is complete, + * prepare the current update: + */ kms->funcs->prepare_commit(kms, state); /* @@ -62,6 +167,49 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) drm_atomic_helper_commit_planes(dev, state, 0); drm_atomic_helper_commit_modeset_enables(dev, state); + if (async) { + struct msm_pending_timer *timer = + &kms->pending_timers[drm_crtc_index(async_crtc)]; + + /* async updates are limited to single-crtc updates: */ + WARN_ON(crtc_mask != drm_crtc_mask(async_crtc)); + + /* + * Start timer if we don't already have an update pending + * on this crtc: + */ + if (!(kms->pending_crtc_mask & crtc_mask)) { + ktime_t vsync_time, wakeup_time; + + kms->pending_crtc_mask |= crtc_mask; + + vsync_time = kms->funcs->vsync_time(kms, async_crtc); + wakeup_time = ktime_sub(vsync_time, ms_to_ktime(1)); + + hrtimer_start(&timer->timer, wakeup_time, + HRTIMER_MODE_ABS); + } + + kms->funcs->disable_commit(kms); + mutex_unlock(&kms->commit_lock); + + /* + * At this point, from drm core's perspective, we + * are done with the atomic update, so we can just + * go ahead and signal that it is done: + */ + drm_atomic_helper_commit_hw_done(state); + drm_atomic_helper_cleanup_planes(dev, state); + + return; + } + + /* + * If there is any async flush pending on updated crtcs, fold + * them into the current flush. + */ + kms->pending_crtc_mask &= ~crtc_mask; + /* * Flush hardware updates: */ @@ -70,12 +218,18 @@ void msm_atomic_commit_tail(struct drm_atomic_state *state) kms->funcs->commit(kms, state); } kms->funcs->flush_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); + /* + * Wait for flush to complete: + */ kms->funcs->wait_flush(kms, crtc_mask); + + mutex_lock(&kms->commit_lock); kms->funcs->complete_commit(kms, crtc_mask); + mutex_unlock(&kms->commit_lock); kms->funcs->disable_commit(kms); drm_atomic_helper_commit_hw_done(state); - drm_atomic_helper_cleanup_planes(dev, state); } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 336a6d0a4cd3..65262a993440 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -532,6 +532,7 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv) ddev->mode_config.normalize_zpos = true; if (kms) { + kms->dev = ddev; ret = kms->funcs->hw_init(kms); if (ret) { DRM_DEV_ERROR(dev, "kms hw init failed: %d\n", ret); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 79d480a7d97d..7d164d5c18b4 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -222,8 +222,12 @@ struct msm_format { uint32_t pixel_format; }; +struct msm_pending_timer; + int msm_atomic_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state); +void msm_atomic_init_pending_timer(struct msm_pending_timer *timer, + struct msm_kms *kms, int crtc_idx); void msm_atomic_commit_tail(struct drm_atomic_state *state); struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev); void msm_atomic_state_clear(struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index 811f5e2c2405..5eafc9686d29 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -33,6 +33,20 @@ struct msm_kms_funcs { /* * Atomic commit handling: + * + * Note that in the case of async commits, the funcs which take + * a crtc_mask (ie. ->flush_commit(), and ->complete_commit()) + * might not be evenly balanced with ->prepare_commit(), however + * each crtc that effected by a ->perpare_commit() (potentially + * multiple times) will eventually (at end of vsync period) be + * flushed and completed. + * + * This has some implications about tracking of cleanup state, + * for example SMP blocks to release after commit completes. Ie. + * cleanup state should be also duplicated in the various + * duplicate_state() methods, as the current cleanup state at + * ->complete_commit() time may have accumulated cleanup work + * from multiple commits. */ /** @@ -45,6 +59,14 @@ struct msm_kms_funcs { void (*enable_commit)(struct msm_kms *kms); void (*disable_commit)(struct msm_kms *kms); + /** + * If the kms backend supports async commit, it should implement + * this method to return the time of the next vsync. This is + * used to determine a time slightly before vsync, for the async + * commit timer to run and complete an async commit. + */ + ktime_t (*vsync_time)(struct msm_kms *kms, struct drm_crtc *crtc); + /** * Prepare for atomic commit. This is called after any previous * (async or otherwise) commit has completed. @@ -109,20 +131,48 @@ struct msm_kms_funcs { #endif }; +struct msm_kms; + +/* + * A per-crtc timer for pending async atomic flushes. Scheduled to expire + * shortly before vblank to flush pending async updates. + */ +struct msm_pending_timer { + struct hrtimer timer; + struct work_struct work; + struct msm_kms *kms; + unsigned crtc_idx; +}; + struct msm_kms { const struct msm_kms_funcs *funcs; + struct drm_device *dev; /* irq number to be passed on to drm_irq_install */ int irq; /* mapper-id used to request GEM buffer mapped for scanout: */ struct msm_gem_address_space *aspace; + + /* + * For async commit, where ->flush_commit() and later happens + * from the crtc's pending_timer close to end of the frame: + */ + struct mutex commit_lock; + unsigned pending_crtc_mask; + struct msm_pending_timer pending_timers[MAX_CRTCS]; }; static inline void msm_kms_init(struct msm_kms *kms, const struct msm_kms_funcs *funcs) { + unsigned i; + + mutex_init(&kms->commit_lock); kms->funcs = funcs; + + for (i = 0; i < ARRAY_SIZE(kms->pending_timers); i++) + msm_atomic_init_pending_timer(&kms->pending_timers[i], kms, i); } struct msm_kms *mdp4_kms_init(struct drm_device *dev); -- 2.21.0 From mboxrd@z Thu Jan 1 00:00:00 1970 From: Rob Clark Subject: [PATCH 08/10] drm/msm: async commit support Date: Thu, 29 Aug 2019 09:45:16 -0700 Message-ID: <20190829164601.11615-9-robdclark@gmail.com> References: <20190829164601.11615-1-robdclark@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: In-Reply-To: <20190829164601.11615-1-robdclark@gmail.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: dri-devel@lists.freedesktop.org Cc: Rob Clark , "open list:DRM DRIVER FOR MSM ADRENO GPU" , David Airlie , "open list:DRM DRIVER FOR MSM ADRENO GPU" , open list , Sean Paul List-Id: dri-devel@lists.freedesktop.org RnJvbTogUm9iIENsYXJrIDxyb2JkY2xhcmtAY2hyb21pdW0ub3JnPgoKTm93IHRoYXQgZmx1c2gv d2FpdC9jb21wbGV0ZSBpcyBkZWNvdXBsZWQgZnJvbSB0aGUgInN5bmNocm9ub3VzIiBwYXJ0IG9m CmF0b21pYyBjb21taXRfdGFpbCgpLCBhZGQgc3VwcG9ydCB0byBkZWZlciBmbHVzaCB0byBhIHRp bWVyIHRoYXQgZXhwaXJlcwpzaG9ydGx5IGJlZm9yZSB2YmxhbmsgZm9yIGFzeW5jIGNvbW1pdHMu ICBJbiB0aGlzIHdheSwgbXVsdGlwbGUgYXRvbWljCmNvbW1pdHMgKGZvciBleGFtcGxlLCBjdXJz b3IgdXBkYXRlcykgY2FuIGJlIGNvYWxlc2NlZCBpbnRvIGEgc2luZ2xlCmZsdXNoIGF0IHRoZSBl bmQgb2YgdGhlIGZyYW1lLgoKdjI6IGRvbid0IGhvbGQgbG9jayBvdmVyIC0+d2FpdF9mbHVzaCgp LCB0byBhdm9pZCBsb2NraW5nIGludGVyYWN0aW9uCiAgICB0aGF0IHdhcyBjYXVzaW5nIGZwcyBk cm9wIHdoZW4gY29tYmluaW5nIHBhZ2UgZmxpcHMgb3Igbm9uLWFzeW5jCiAgICBhdG9taWMgY29t bWl0cyBhbmQgbG90cyBvZiBsZWdhY3kgY3Vyc29yIHVwZGF0ZXMKClNpZ25lZC1vZmYtYnk6IFJv YiBDbGFyayA8cm9iZGNsYXJrQGNocm9taXVtLm9yZz4KLS0tCiBkcml2ZXJzL2dwdS9kcm0vbXNt L21zbV9hdG9taWMuYyB8IDE1NiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKystCiBkcml2 ZXJzL2dwdS9kcm0vbXNtL21zbV9kcnYuYyAgICB8ICAgMSArCiBkcml2ZXJzL2dwdS9kcm0vbXNt L21zbV9kcnYuaCAgICB8ICAgNCArCiBkcml2ZXJzL2dwdS9kcm0vbXNtL21zbV9rbXMuaCAgICB8 ICA1MCArKysrKysrKysrCiA0IGZpbGVzIGNoYW5nZWQsIDIxMCBpbnNlcnRpb25zKCspLCAxIGRl bGV0aW9uKC0pCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL21zbS9tc21fYXRvbWljLmMg Yi9kcml2ZXJzL2dwdS9kcm0vbXNtL21zbV9hdG9taWMuYwppbmRleCA2MTRmYjljNWJiNTguLjhm OGY3NDMzN2NiNCAxMDA2NDQKLS0tIGEvZHJpdmVycy9ncHUvZHJtL21zbS9tc21fYXRvbWljLmMK KysrIGIvZHJpdmVycy9ncHUvZHJtL21zbS9tc21fYXRvbWljLmMKQEAgLTI5LDYgKzI5LDk1IEBA IGludCBtc21fYXRvbWljX3ByZXBhcmVfZmIoc3RydWN0IGRybV9wbGFuZSAqcGxhbmUsCiAJcmV0 dXJuIG1zbV9mcmFtZWJ1ZmZlcl9wcmVwYXJlKG5ld19zdGF0ZS0+ZmIsIGttcy0+YXNwYWNlKTsK IH0KIAorc3RhdGljIHZvaWQgbXNtX2F0b21pY19hc3luY19jb21taXQoc3RydWN0IG1zbV9rbXMg KmttcywgaW50IGNydGNfaWR4KQoreworCXVuc2lnbmVkIGNydGNfbWFzayA9IEJJVChjcnRjX2lk eCk7CisKKwltdXRleF9sb2NrKCZrbXMtPmNvbW1pdF9sb2NrKTsKKworCWlmICghKGttcy0+cGVu ZGluZ19jcnRjX21hc2sgJiBjcnRjX21hc2spKSB7CisJCW11dGV4X3VubG9jaygma21zLT5jb21t aXRfbG9jayk7CisJCXJldHVybjsKKwl9CisKKwlrbXMtPnBlbmRpbmdfY3J0Y19tYXNrICY9IH5j cnRjX21hc2s7CisKKwlrbXMtPmZ1bmNzLT5lbmFibGVfY29tbWl0KGttcyk7CisKKwkvKgorCSAq IEZsdXNoIGhhcmR3YXJlIHVwZGF0ZXM6CisJICovCisJRFJNX0RFQlVHX0FUT01JQygidHJpZ2dl cmluZyBhc3luYyBjb21taXRcbiIpOworCWttcy0+ZnVuY3MtPmZsdXNoX2NvbW1pdChrbXMsIGNy dGNfbWFzayk7CisJbXV0ZXhfdW5sb2NrKCZrbXMtPmNvbW1pdF9sb2NrKTsKKworCS8qCisJICog V2FpdCBmb3IgZmx1c2ggdG8gY29tcGxldGU6CisJICovCisJa21zLT5mdW5jcy0+d2FpdF9mbHVz aChrbXMsIGNydGNfbWFzayk7CisKKwltdXRleF9sb2NrKCZrbXMtPmNvbW1pdF9sb2NrKTsKKwlr bXMtPmZ1bmNzLT5jb21wbGV0ZV9jb21taXQoa21zLCBjcnRjX21hc2spOworCW11dGV4X3VubG9j aygma21zLT5jb21taXRfbG9jayk7CisJa21zLT5mdW5jcy0+ZGlzYWJsZV9jb21taXQoa21zKTsK K30KKworc3RhdGljIGVudW0gaHJ0aW1lcl9yZXN0YXJ0IG1zbV9hdG9taWNfcGVuZGluZ190aW1l cihzdHJ1Y3QgaHJ0aW1lciAqdCkKK3sKKwlzdHJ1Y3QgbXNtX3BlbmRpbmdfdGltZXIgKnRpbWVy ID0gY29udGFpbmVyX29mKHQsCisJCQlzdHJ1Y3QgbXNtX3BlbmRpbmdfdGltZXIsIHRpbWVyKTsK KwlzdHJ1Y3QgbXNtX2RybV9wcml2YXRlICpwcml2ID0gdGltZXItPmttcy0+ZGV2LT5kZXZfcHJp dmF0ZTsKKworCXF1ZXVlX3dvcmsocHJpdi0+d3EsICZ0aW1lci0+d29yayk7CisKKwlyZXR1cm4g SFJUSU1FUl9OT1JFU1RBUlQ7Cit9CisKK3N0YXRpYyB2b2lkIG1zbV9hdG9taWNfcGVuZGluZ193 b3JrKHN0cnVjdCB3b3JrX3N0cnVjdCAqd29yaykKK3sKKwlzdHJ1Y3QgbXNtX3BlbmRpbmdfdGlt ZXIgKnRpbWVyID0gY29udGFpbmVyX29mKHdvcmssCisJCQlzdHJ1Y3QgbXNtX3BlbmRpbmdfdGlt ZXIsIHdvcmspOworCisJbXNtX2F0b21pY19hc3luY19jb21taXQodGltZXItPmttcywgdGltZXIt PmNydGNfaWR4KTsKK30KKwordm9pZCBtc21fYXRvbWljX2luaXRfcGVuZGluZ190aW1lcihzdHJ1 Y3QgbXNtX3BlbmRpbmdfdGltZXIgKnRpbWVyLAorCQlzdHJ1Y3QgbXNtX2ttcyAqa21zLCBpbnQg Y3J0Y19pZHgpCit7CisJdGltZXItPmttcyA9IGttczsKKwl0aW1lci0+Y3J0Y19pZHggPSBjcnRj X2lkeDsKKwlocnRpbWVyX2luaXQoJnRpbWVyLT50aW1lciwgQ0xPQ0tfTU9OT1RPTklDLCBIUlRJ TUVSX01PREVfQUJTKTsKKwl0aW1lci0+dGltZXIuZnVuY3Rpb24gPSBtc21fYXRvbWljX3BlbmRp bmdfdGltZXI7CisJSU5JVF9XT1JLKCZ0aW1lci0+d29yaywgbXNtX2F0b21pY19wZW5kaW5nX3dv cmspOworfQorCitzdGF0aWMgYm9vbCBjYW5fZG9fYXN5bmMoc3RydWN0IGRybV9hdG9taWNfc3Rh dGUgKnN0YXRlLAorCQlzdHJ1Y3QgZHJtX2NydGMgKiphc3luY19jcnRjKQoreworCXN0cnVjdCBk cm1fY29ubmVjdG9yX3N0YXRlICpjb25uZWN0b3Jfc3RhdGU7CisJc3RydWN0IGRybV9jb25uZWN0 b3IgKmNvbm5lY3RvcjsKKwlzdHJ1Y3QgZHJtX2NydGNfc3RhdGUgKmNydGNfc3RhdGU7CisJc3Ry dWN0IGRybV9jcnRjICpjcnRjOworCWludCBpLCBudW1fY3J0Y3MgPSAwOworCisJaWYgKCEoc3Rh dGUtPmxlZ2FjeV9jdXJzb3JfdXBkYXRlIHx8IHN0YXRlLT5hc3luY191cGRhdGUpKQorCQlyZXR1 cm4gZmFsc2U7CisKKwkvKiBhbnkgY29ubmVjdG9yIGNoYW5nZSwgbWVhbnMgc2xvdyBwYXRoOiAq LworCWZvcl9lYWNoX25ld19jb25uZWN0b3JfaW5fc3RhdGUoc3RhdGUsIGNvbm5lY3RvciwgY29u bmVjdG9yX3N0YXRlLCBpKQorCQlyZXR1cm4gZmFsc2U7CisKKwlmb3JfZWFjaF9uZXdfY3J0Y19p bl9zdGF0ZShzdGF0ZSwgY3J0YywgY3J0Y19zdGF0ZSwgaSkgeworCQlpZiAoZHJtX2F0b21pY19j cnRjX25lZWRzX21vZGVzZXQoY3J0Y19zdGF0ZSkpCisJCQlyZXR1cm4gZmFsc2U7CisJCWlmICgr K251bV9jcnRjcyA+IDEpCisJCQlyZXR1cm4gZmFsc2U7CisJCSphc3luY19jcnRjID0gY3J0YzsK Kwl9CisKKwlyZXR1cm4gdHJ1ZTsKK30KKwogLyogR2V0IGJpdG1hc2sgb2YgY3J0Y3MgdGhhdCB3 aWxsIG5lZWQgdG8gYmUgZmx1c2hlZC4gIFRoZSBiaXRtYXNrCiAgKiBjYW4gYmUgdXNlZCB3aXRo IGZvcl9lYWNoX2NydGNfbWFzaygpIGl0ZXJhdG9yLCB0byBpdGVyYXRlCiAgKiBlZmZlY3RlZCBj cnRjcyB3aXRob3V0IG5lZWRpbmcgdG8gcHJlc2VydmUgdGhlIGF0b21pYyBzdGF0ZS4KQEAgLTUw LDkgKzEzOSwyNSBAQCB2b2lkIG1zbV9hdG9taWNfY29tbWl0X3RhaWwoc3RydWN0IGRybV9hdG9t aWNfc3RhdGUgKnN0YXRlKQogCXN0cnVjdCBkcm1fZGV2aWNlICpkZXYgPSBzdGF0ZS0+ZGV2Owog CXN0cnVjdCBtc21fZHJtX3ByaXZhdGUgKnByaXYgPSBkZXYtPmRldl9wcml2YXRlOwogCXN0cnVj dCBtc21fa21zICprbXMgPSBwcml2LT5rbXM7CisJc3RydWN0IGRybV9jcnRjICphc3luY19jcnRj ID0gTlVMTDsKIAl1bnNpZ25lZCBjcnRjX21hc2sgPSBnZXRfY3J0Y19tYXNrKHN0YXRlKTsKKwli b29sIGFzeW5jID0ga21zLT5mdW5jcy0+dnN5bmNfdGltZSAmJgorCQkJY2FuX2RvX2FzeW5jKHN0 YXRlLCAmYXN5bmNfY3J0Yyk7CiAKIAlrbXMtPmZ1bmNzLT5lbmFibGVfY29tbWl0KGttcyk7CisK KwkvKgorCSAqIEVuc3VyZSBhbnkgcHJldmlvdXMgKHBvdGVudGlhbGx5IGFzeW5jKSBjb21taXQg aGFzCisJICogY29tcGxldGVkOgorCSAqLworCWttcy0+ZnVuY3MtPndhaXRfZmx1c2goa21zLCBj cnRjX21hc2spOworCisJbXV0ZXhfbG9jaygma21zLT5jb21taXRfbG9jayk7CisKKwkvKgorCSAq IE5vdyB0aGF0IHRoZXJlIGlzIG5vIGluLXByb2dyZXNzIGZsdXNoIGlzIGNvbXBsZXRlLAorCSAq IHByZXBhcmUgdGhlIGN1cnJlbnQgdXBkYXRlOgorCSAqLwogCWttcy0+ZnVuY3MtPnByZXBhcmVf Y29tbWl0KGttcywgc3RhdGUpOwogCiAJLyoKQEAgLTYyLDYgKzE2Nyw0OSBAQCB2b2lkIG1zbV9h dG9taWNfY29tbWl0X3RhaWwoc3RydWN0IGRybV9hdG9taWNfc3RhdGUgKnN0YXRlKQogCWRybV9h dG9taWNfaGVscGVyX2NvbW1pdF9wbGFuZXMoZGV2LCBzdGF0ZSwgMCk7CiAJZHJtX2F0b21pY19o ZWxwZXJfY29tbWl0X21vZGVzZXRfZW5hYmxlcyhkZXYsIHN0YXRlKTsKIAorCWlmIChhc3luYykg eworCQlzdHJ1Y3QgbXNtX3BlbmRpbmdfdGltZXIgKnRpbWVyID0KKwkJCSZrbXMtPnBlbmRpbmdf dGltZXJzW2RybV9jcnRjX2luZGV4KGFzeW5jX2NydGMpXTsKKworCQkvKiBhc3luYyB1cGRhdGVz IGFyZSBsaW1pdGVkIHRvIHNpbmdsZS1jcnRjIHVwZGF0ZXM6ICovCisJCVdBUk5fT04oY3J0Y19t YXNrICE9IGRybV9jcnRjX21hc2soYXN5bmNfY3J0YykpOworCisJCS8qCisJCSAqIFN0YXJ0IHRp bWVyIGlmIHdlIGRvbid0IGFscmVhZHkgaGF2ZSBhbiB1cGRhdGUgcGVuZGluZworCQkgKiBvbiB0 aGlzIGNydGM6CisJCSAqLworCQlpZiAoIShrbXMtPnBlbmRpbmdfY3J0Y19tYXNrICYgY3J0Y19t YXNrKSkgeworCQkJa3RpbWVfdCB2c3luY190aW1lLCB3YWtldXBfdGltZTsKKworCQkJa21zLT5w ZW5kaW5nX2NydGNfbWFzayB8PSBjcnRjX21hc2s7CisKKwkJCXZzeW5jX3RpbWUgPSBrbXMtPmZ1 bmNzLT52c3luY190aW1lKGttcywgYXN5bmNfY3J0Yyk7CisJCQl3YWtldXBfdGltZSA9IGt0aW1l X3N1Yih2c3luY190aW1lLCBtc190b19rdGltZSgxKSk7CisKKwkJCWhydGltZXJfc3RhcnQoJnRp bWVyLT50aW1lciwgd2FrZXVwX3RpbWUsCisJCQkJCUhSVElNRVJfTU9ERV9BQlMpOworCQl9CisK KwkJa21zLT5mdW5jcy0+ZGlzYWJsZV9jb21taXQoa21zKTsKKwkJbXV0ZXhfdW5sb2NrKCZrbXMt PmNvbW1pdF9sb2NrKTsKKworCQkvKgorCQkgKiBBdCB0aGlzIHBvaW50LCBmcm9tIGRybSBjb3Jl J3MgcGVyc3BlY3RpdmUsIHdlCisJCSAqIGFyZSBkb25lIHdpdGggdGhlIGF0b21pYyB1cGRhdGUs IHNvIHdlIGNhbiBqdXN0CisJCSAqIGdvIGFoZWFkIGFuZCBzaWduYWwgdGhhdCBpdCBpcyBkb25l OgorCQkgKi8KKwkJZHJtX2F0b21pY19oZWxwZXJfY29tbWl0X2h3X2RvbmUoc3RhdGUpOworCQlk cm1fYXRvbWljX2hlbHBlcl9jbGVhbnVwX3BsYW5lcyhkZXYsIHN0YXRlKTsKKworCQlyZXR1cm47 CisJfQorCisJLyoKKwkgKiBJZiB0aGVyZSBpcyBhbnkgYXN5bmMgZmx1c2ggcGVuZGluZyBvbiB1 cGRhdGVkIGNydGNzLCBmb2xkCisJICogdGhlbSBpbnRvIHRoZSBjdXJyZW50IGZsdXNoLgorCSAq LworCWttcy0+cGVuZGluZ19jcnRjX21hc2sgJj0gfmNydGNfbWFzazsKKwogCS8qCiAJICogRmx1 c2ggaGFyZHdhcmUgdXBkYXRlczoKIAkgKi8KQEAgLTcwLDEyICsyMTgsMTggQEAgdm9pZCBtc21f YXRvbWljX2NvbW1pdF90YWlsKHN0cnVjdCBkcm1fYXRvbWljX3N0YXRlICpzdGF0ZSkKIAkJa21z LT5mdW5jcy0+Y29tbWl0KGttcywgc3RhdGUpOwogCX0KIAlrbXMtPmZ1bmNzLT5mbHVzaF9jb21t aXQoa21zLCBjcnRjX21hc2spOworCW11dGV4X3VubG9jaygma21zLT5jb21taXRfbG9jayk7CiAK KwkvKgorCSAqIFdhaXQgZm9yIGZsdXNoIHRvIGNvbXBsZXRlOgorCSAqLwogCWttcy0+ZnVuY3Mt PndhaXRfZmx1c2goa21zLCBjcnRjX21hc2spOworCisJbXV0ZXhfbG9jaygma21zLT5jb21taXRf bG9jayk7CiAJa21zLT5mdW5jcy0+Y29tcGxldGVfY29tbWl0KGttcywgY3J0Y19tYXNrKTsKKwlt dXRleF91bmxvY2soJmttcy0+Y29tbWl0X2xvY2spOwogCWttcy0+ZnVuY3MtPmRpc2FibGVfY29t bWl0KGttcyk7CiAKIAlkcm1fYXRvbWljX2hlbHBlcl9jb21taXRfaHdfZG9uZShzdGF0ZSk7Ci0K IAlkcm1fYXRvbWljX2hlbHBlcl9jbGVhbnVwX3BsYW5lcyhkZXYsIHN0YXRlKTsKIH0KZGlmZiAt LWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9tc20vbXNtX2Rydi5jIGIvZHJpdmVycy9ncHUvZHJtL21z bS9tc21fZHJ2LmMKaW5kZXggMzM2YTZkMGE0Y2QzLi42NTI2MmE5OTM0NDAgMTAwNjQ0Ci0tLSBh L2RyaXZlcnMvZ3B1L2RybS9tc20vbXNtX2Rydi5jCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9tc20v bXNtX2Rydi5jCkBAIC01MzIsNiArNTMyLDcgQEAgc3RhdGljIGludCBtc21fZHJtX2luaXQoc3Ry dWN0IGRldmljZSAqZGV2LCBzdHJ1Y3QgZHJtX2RyaXZlciAqZHJ2KQogCWRkZXYtPm1vZGVfY29u ZmlnLm5vcm1hbGl6ZV96cG9zID0gdHJ1ZTsKIAogCWlmIChrbXMpIHsKKwkJa21zLT5kZXYgPSBk ZGV2OwogCQlyZXQgPSBrbXMtPmZ1bmNzLT5od19pbml0KGttcyk7CiAJCWlmIChyZXQpIHsKIAkJ CURSTV9ERVZfRVJST1IoZGV2LCAia21zIGh3IGluaXQgZmFpbGVkOiAlZFxuIiwgcmV0KTsKZGlm ZiAtLWdpdCBhL2RyaXZlcnMvZ3B1L2RybS9tc20vbXNtX2Rydi5oIGIvZHJpdmVycy9ncHUvZHJt L21zbS9tc21fZHJ2LmgKaW5kZXggNzlkNDgwYTdkOTdkLi43ZDE2NGQ1YzE4YjQgMTAwNjQ0Ci0t LSBhL2RyaXZlcnMvZ3B1L2RybS9tc20vbXNtX2Rydi5oCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9t c20vbXNtX2Rydi5oCkBAIC0yMjIsOCArMjIyLDEyIEBAIHN0cnVjdCBtc21fZm9ybWF0IHsKIAl1 aW50MzJfdCBwaXhlbF9mb3JtYXQ7CiB9OwogCitzdHJ1Y3QgbXNtX3BlbmRpbmdfdGltZXI7CisK IGludCBtc21fYXRvbWljX3ByZXBhcmVfZmIoc3RydWN0IGRybV9wbGFuZSAqcGxhbmUsCiAJCQkg IHN0cnVjdCBkcm1fcGxhbmVfc3RhdGUgKm5ld19zdGF0ZSk7Cit2b2lkIG1zbV9hdG9taWNfaW5p dF9wZW5kaW5nX3RpbWVyKHN0cnVjdCBtc21fcGVuZGluZ190aW1lciAqdGltZXIsCisJCXN0cnVj dCBtc21fa21zICprbXMsIGludCBjcnRjX2lkeCk7CiB2b2lkIG1zbV9hdG9taWNfY29tbWl0X3Rh aWwoc3RydWN0IGRybV9hdG9taWNfc3RhdGUgKnN0YXRlKTsKIHN0cnVjdCBkcm1fYXRvbWljX3N0 YXRlICptc21fYXRvbWljX3N0YXRlX2FsbG9jKHN0cnVjdCBkcm1fZGV2aWNlICpkZXYpOwogdm9p ZCBtc21fYXRvbWljX3N0YXRlX2NsZWFyKHN0cnVjdCBkcm1fYXRvbWljX3N0YXRlICpzdGF0ZSk7 CmRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vbXNtL21zbV9rbXMuaCBiL2RyaXZlcnMvZ3B1 L2RybS9tc20vbXNtX2ttcy5oCmluZGV4IDgxMWY1ZTJjMjQwNS4uNWVhZmM5Njg2ZDI5IDEwMDY0 NAotLS0gYS9kcml2ZXJzL2dwdS9kcm0vbXNtL21zbV9rbXMuaAorKysgYi9kcml2ZXJzL2dwdS9k cm0vbXNtL21zbV9rbXMuaApAQCAtMzMsNiArMzMsMjAgQEAgc3RydWN0IG1zbV9rbXNfZnVuY3Mg ewogCiAJLyoKIAkgKiBBdG9taWMgY29tbWl0IGhhbmRsaW5nOgorCSAqCisJICogTm90ZSB0aGF0 IGluIHRoZSBjYXNlIG9mIGFzeW5jIGNvbW1pdHMsIHRoZSBmdW5jcyB3aGljaCB0YWtlCisJICog YSBjcnRjX21hc2sgKGllLiAtPmZsdXNoX2NvbW1pdCgpLCBhbmQgLT5jb21wbGV0ZV9jb21taXQo KSkKKwkgKiBtaWdodCBub3QgYmUgZXZlbmx5IGJhbGFuY2VkIHdpdGggLT5wcmVwYXJlX2NvbW1p dCgpLCBob3dldmVyCisJICogZWFjaCBjcnRjIHRoYXQgZWZmZWN0ZWQgYnkgYSAtPnBlcnBhcmVf Y29tbWl0KCkgKHBvdGVudGlhbGx5CisJICogbXVsdGlwbGUgdGltZXMpIHdpbGwgZXZlbnR1YWxs eSAoYXQgZW5kIG9mIHZzeW5jIHBlcmlvZCkgYmUKKwkgKiBmbHVzaGVkIGFuZCBjb21wbGV0ZWQu CisJICoKKwkgKiBUaGlzIGhhcyBzb21lIGltcGxpY2F0aW9ucyBhYm91dCB0cmFja2luZyBvZiBj bGVhbnVwIHN0YXRlLAorCSAqIGZvciBleGFtcGxlIFNNUCBibG9ja3MgdG8gcmVsZWFzZSBhZnRl ciBjb21taXQgY29tcGxldGVzLiAgSWUuCisJICogY2xlYW51cCBzdGF0ZSBzaG91bGQgYmUgYWxz byBkdXBsaWNhdGVkIGluIHRoZSB2YXJpb3VzCisJICogZHVwbGljYXRlX3N0YXRlKCkgbWV0aG9k cywgYXMgdGhlIGN1cnJlbnQgY2xlYW51cCBzdGF0ZSBhdAorCSAqIC0+Y29tcGxldGVfY29tbWl0 KCkgdGltZSBtYXkgaGF2ZSBhY2N1bXVsYXRlZCBjbGVhbnVwIHdvcmsKKwkgKiBmcm9tIG11bHRp cGxlIGNvbW1pdHMuCiAJICovCiAKIAkvKioKQEAgLTQ1LDYgKzU5LDE0IEBAIHN0cnVjdCBtc21f a21zX2Z1bmNzIHsKIAl2b2lkICgqZW5hYmxlX2NvbW1pdCkoc3RydWN0IG1zbV9rbXMgKmttcyk7 CiAJdm9pZCAoKmRpc2FibGVfY29tbWl0KShzdHJ1Y3QgbXNtX2ttcyAqa21zKTsKIAorCS8qKgor CSAqIElmIHRoZSBrbXMgYmFja2VuZCBzdXBwb3J0cyBhc3luYyBjb21taXQsIGl0IHNob3VsZCBp bXBsZW1lbnQKKwkgKiB0aGlzIG1ldGhvZCB0byByZXR1cm4gdGhlIHRpbWUgb2YgdGhlIG5leHQg dnN5bmMuICBUaGlzIGlzCisJICogdXNlZCB0byBkZXRlcm1pbmUgYSB0aW1lIHNsaWdodGx5IGJl Zm9yZSB2c3luYywgZm9yIHRoZSBhc3luYworCSAqIGNvbW1pdCB0aW1lciB0byBydW4gYW5kIGNv bXBsZXRlIGFuIGFzeW5jIGNvbW1pdC4KKwkgKi8KKwlrdGltZV90ICgqdnN5bmNfdGltZSkoc3Ry dWN0IG1zbV9rbXMgKmttcywgc3RydWN0IGRybV9jcnRjICpjcnRjKTsKKwogCS8qKgogCSAqIFBy ZXBhcmUgZm9yIGF0b21pYyBjb21taXQuICBUaGlzIGlzIGNhbGxlZCBhZnRlciBhbnkgcHJldmlv dXMKIAkgKiAoYXN5bmMgb3Igb3RoZXJ3aXNlKSBjb21taXQgaGFzIGNvbXBsZXRlZC4KQEAgLTEw OSwyMCArMTMxLDQ4IEBAIHN0cnVjdCBtc21fa21zX2Z1bmNzIHsKICNlbmRpZgogfTsKIAorc3Ry dWN0IG1zbV9rbXM7CisKKy8qCisgKiBBIHBlci1jcnRjIHRpbWVyIGZvciBwZW5kaW5nIGFzeW5j IGF0b21pYyBmbHVzaGVzLiAgU2NoZWR1bGVkIHRvIGV4cGlyZQorICogc2hvcnRseSBiZWZvcmUg dmJsYW5rIHRvIGZsdXNoIHBlbmRpbmcgYXN5bmMgdXBkYXRlcy4KKyAqLworc3RydWN0IG1zbV9w ZW5kaW5nX3RpbWVyIHsKKwlzdHJ1Y3QgaHJ0aW1lciB0aW1lcjsKKwlzdHJ1Y3Qgd29ya19zdHJ1 Y3Qgd29yazsKKwlzdHJ1Y3QgbXNtX2ttcyAqa21zOworCXVuc2lnbmVkIGNydGNfaWR4OworfTsK Kwogc3RydWN0IG1zbV9rbXMgewogCWNvbnN0IHN0cnVjdCBtc21fa21zX2Z1bmNzICpmdW5jczsK KwlzdHJ1Y3QgZHJtX2RldmljZSAqZGV2OwogCiAJLyogaXJxIG51bWJlciB0byBiZSBwYXNzZWQg b24gdG8gZHJtX2lycV9pbnN0YWxsICovCiAJaW50IGlycTsKIAogCS8qIG1hcHBlci1pZCB1c2Vk IHRvIHJlcXVlc3QgR0VNIGJ1ZmZlciBtYXBwZWQgZm9yIHNjYW5vdXQ6ICovCiAJc3RydWN0IG1z bV9nZW1fYWRkcmVzc19zcGFjZSAqYXNwYWNlOworCisJLyoKKwkgKiBGb3IgYXN5bmMgY29tbWl0 LCB3aGVyZSAtPmZsdXNoX2NvbW1pdCgpIGFuZCBsYXRlciBoYXBwZW5zCisJICogZnJvbSB0aGUg Y3J0YydzIHBlbmRpbmdfdGltZXIgY2xvc2UgdG8gZW5kIG9mIHRoZSBmcmFtZToKKwkgKi8KKwlz dHJ1Y3QgbXV0ZXggY29tbWl0X2xvY2s7CisJdW5zaWduZWQgcGVuZGluZ19jcnRjX21hc2s7CisJ c3RydWN0IG1zbV9wZW5kaW5nX3RpbWVyIHBlbmRpbmdfdGltZXJzW01BWF9DUlRDU107CiB9Owog CiBzdGF0aWMgaW5saW5lIHZvaWQgbXNtX2ttc19pbml0KHN0cnVjdCBtc21fa21zICprbXMsCiAJ CWNvbnN0IHN0cnVjdCBtc21fa21zX2Z1bmNzICpmdW5jcykKIHsKKwl1bnNpZ25lZCBpOworCisJ bXV0ZXhfaW5pdCgma21zLT5jb21taXRfbG9jayk7CiAJa21zLT5mdW5jcyA9IGZ1bmNzOworCisJ Zm9yIChpID0gMDsgaSA8IEFSUkFZX1NJWkUoa21zLT5wZW5kaW5nX3RpbWVycyk7IGkrKykKKwkJ bXNtX2F0b21pY19pbml0X3BlbmRpbmdfdGltZXIoJmttcy0+cGVuZGluZ190aW1lcnNbaV0sIGtt cywgaSk7CiB9CiAKIHN0cnVjdCBtc21fa21zICptZHA0X2ttc19pbml0KHN0cnVjdCBkcm1fZGV2 aWNlICpkZXYpOwotLSAKMi4yMS4wCgpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVl ZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5m by9kcmktZGV2ZWw=