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=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_SANE_1 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 82184C07E96 for ; Tue, 6 Jul 2021 19:19:40 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 48A2F6192B for ; Tue, 6 Jul 2021 19:19:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 48A2F6192B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B3BD06E59D; Tue, 6 Jul 2021 19:19:39 +0000 (UTC) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9499E6E59D; Tue, 6 Jul 2021 19:19:37 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6200,9189,10037"; a="206169110" X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="206169110" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 12:19:25 -0700 X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="457182410" Received: from johnharr-mobl1.amr.corp.intel.com (HELO [10.212.151.177]) ([10.212.151.177]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 12:19:25 -0700 Subject: Re: [PATCH 6/7] drm/i915/guc: Optimize CTB writes and reads To: Michal Wajdeczko , Matthew Brost , intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org References: <20210701171550.49353-1-matthew.brost@intel.com> <20210701171550.49353-7-matthew.brost@intel.com> <3147114d-4b4b-1a42-c40b-8d8be870e633@intel.com> From: John Harrison Message-ID: Date: Tue, 6 Jul 2021 12:19:24 -0700 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-GB X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" On 7/6/2021 12:12, Michal Wajdeczko wrote: > On 06.07.2021 21:00, John Harrison wrote: >> On 7/1/2021 10:15, Matthew Brost wrote: >>> CTB writes are now in the path of command submission and should be >>> optimized for performance. Rather than reading CTB descriptor values >>> (e.g. head, tail) which could result in accesses across the PCIe bus, >>> store shadow local copies and only read/write the descriptor values when >>> absolutely necessary. Also store the current space in the each channel >>> locally. >>> >>> v2: >>>   (Michel) >>>    - Add additional sanity checks for head / tail pointers >>>    - Use GUC_CTB_HDR_LEN rather than magic 1 >>> >>> Signed-off-by: John Harrison >>> Signed-off-by: Matthew Brost >>> --- >>>   drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c | 88 +++++++++++++++-------- >>>   drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h |  6 ++ >>>   2 files changed, 65 insertions(+), 29 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>> b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>> index a9cb7b608520..5b8b4ff609e2 100644 >>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c >>> @@ -130,6 +130,10 @@ static void guc_ct_buffer_desc_init(struct >>> guc_ct_buffer_desc *desc) >>>   static void guc_ct_buffer_reset(struct intel_guc_ct_buffer *ctb) >>>   { >>>       ctb->broken = false; >>> +    ctb->tail = 0; >>> +    ctb->head = 0; >>> +    ctb->space = CIRC_SPACE(ctb->tail, ctb->head, ctb->size); >>> + >>>       guc_ct_buffer_desc_init(ctb->desc); >>>   } >>>   @@ -383,10 +387,8 @@ static int ct_write(struct intel_guc_ct *ct, >>>   { >>>       struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; >>>       struct guc_ct_buffer_desc *desc = ctb->desc; >>> -    u32 head = desc->head; >>> -    u32 tail = desc->tail; >>> +    u32 tail = ctb->tail; >>>       u32 size = ctb->size; >>> -    u32 used; >>>       u32 header; >>>       u32 hxg; >>>       u32 *cmds = ctb->cmds; >>> @@ -395,25 +397,22 @@ static int ct_write(struct intel_guc_ct *ct, >>>       if (unlikely(desc->status)) >>>           goto corrupted; >>>   -    if (unlikely((tail | head) >= size)) { >>> +    GEM_BUG_ON(tail > size); >>> + >>> +#ifdef CONFIG_DRM_I915_DEBUG_GUC >>> +    if (unlikely(tail != READ_ONCE(desc->tail))) { >>> +        CT_ERROR(ct, "Tail was modified %u != %u\n", >>> +             desc->tail, ctb->tail); >>> +        desc->status |= GUC_CTB_STATUS_MISMATCH; >>> +        goto corrupted; >>> +    } >>> +    if (unlikely((desc->tail | desc->head) >= size)) { >>>           CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n", >>> -             head, tail, size); >>> +             desc->head, desc->tail, size); >>>           desc->status |= GUC_CTB_STATUS_OVERFLOW; >>>           goto corrupted; >>>       } >>> - >>> -    /* >>> -     * tail == head condition indicates empty. GuC FW does not support >>> -     * using up the entire buffer to get tail == head meaning full. >>> -     */ >>> -    if (tail < head) >>> -        used = (size - head) + tail; >>> -    else >>> -        used = tail - head; >>> - >>> -    /* make sure there is a space including extra dw for the fence */ >>> -    if (unlikely(used + len + GUC_CTB_HDR_LEN >= size)) >>> -        return -ENOSPC; >>> +#endif >>>         /* >>>        * dw0: CT header (including fence) >>> @@ -454,7 +453,9 @@ static int ct_write(struct intel_guc_ct *ct, >>>       write_barrier(ct); >>>         /* now update descriptor */ >>> +    ctb->tail = tail; >>>       WRITE_ONCE(desc->tail, tail); >>> +    ctb->space -= len + GUC_CTB_HDR_LEN; >>>         return 0; >>>   @@ -470,7 +471,7 @@ static int ct_write(struct intel_guc_ct *ct, >>>    * @req:    pointer to pending request >>>    * @status:    placeholder for status >>>    * >>> - * For each sent request, Guc shall send bac CT response message. >>> + * For each sent request, GuC shall send back CT response message. >>>    * Our message handler will update status of tracked request once >>>    * response message with given fence is received. Wait here and >>>    * check for valid response status value. >>> @@ -526,24 +527,35 @@ static inline bool ct_deadlocked(struct >>> intel_guc_ct *ct) >>>       return ret; >>>   } >>>   -static inline bool h2g_has_room(struct intel_guc_ct_buffer *ctb, >>> u32 len_dw) >>> +static inline bool h2g_has_room(struct intel_guc_ct *ct, u32 len_dw) >>>   { >>> -    struct guc_ct_buffer_desc *desc = ctb->desc; >>> -    u32 head = READ_ONCE(desc->head); >>> +    struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; >>> +    u32 head; >>>       u32 space; >>>   -    space = CIRC_SPACE(desc->tail, head, ctb->size); >>> +    if (ctb->space >= len_dw) >>> +        return true; >>> + >>> +    head = READ_ONCE(ctb->desc->head); >>> +    if (unlikely(head > ctb->size)) { >>> +        CT_ERROR(ct, "Corrupted descriptor head=%u tail=%u size=%u\n", >>> +             ctb->desc->head, ctb->desc->tail, ctb->size); >>> +        ctb->desc->status |= GUC_CTB_STATUS_OVERFLOW; >>> +        ctb->broken = true; >>> +        return false; >>> +    } >>> + >>> +    space = CIRC_SPACE(ctb->tail, head, ctb->size); >>> +    ctb->space = space; >>>         return space >= len_dw; >>>   } >>>     static int has_room_nb(struct intel_guc_ct *ct, u32 len_dw) >>>   { >>> -    struct intel_guc_ct_buffer *ctb = &ct->ctbs.send; >>> - >>>       lockdep_assert_held(&ct->ctbs.send.lock); >>>   -    if (unlikely(!h2g_has_room(ctb, len_dw))) { >>> +    if (unlikely(!h2g_has_room(ct, len_dw))) { >>>           if (ct->stall_time == KTIME_MAX) >>>               ct->stall_time = ktime_get(); >>>   @@ -613,7 +625,7 @@ static int ct_send(struct intel_guc_ct *ct, >>>        */ >>>   retry: >>>       spin_lock_irqsave(&ctb->lock, flags); >>> -    if (unlikely(!h2g_has_room(ctb, len + GUC_CTB_HDR_LEN))) { >>> +    if (unlikely(!h2g_has_room(ct, len + GUC_CTB_HDR_LEN))) { >>>           if (ct->stall_time == KTIME_MAX) >>>               ct->stall_time = ktime_get(); >>>           spin_unlock_irqrestore(&ctb->lock, flags); >>> @@ -733,7 +745,7 @@ static int ct_read(struct intel_guc_ct *ct, struct >>> ct_incoming_msg **msg) >>>   { >>>       struct intel_guc_ct_buffer *ctb = &ct->ctbs.recv; >>>       struct guc_ct_buffer_desc *desc = ctb->desc; >>> -    u32 head = desc->head; >>> +    u32 head = ctb->head; >>>       u32 tail = desc->tail; >>>       u32 size = ctb->size; >>>       u32 *cmds = ctb->cmds; >>> @@ -748,12 +760,29 @@ static int ct_read(struct intel_guc_ct *ct, >>> struct ct_incoming_msg **msg) >>>       if (unlikely(desc->status)) >>>           goto corrupted; >>>   -    if (unlikely((tail | head) >= size)) { >>> +    GEM_BUG_ON(head > size); >> Is the BUG_ON necessary given that both options below do the same check >> but as a corrupted buffer test (with subsequent recovery by GT reset?) >> rather than killing the driver. > "head" and "size" are now fully owned by the driver. > BUGON here is to make sure driver is coded correctly. The point is that both sides of the #if below also validate head. So first there is a BUG_ON, then there is the same test but without blowing the driver apart. One or the other is not required. My vote would be to keep the recoverable test rather than the BUG_ON. John. > >>> + >>> +#ifdef CONFIG_DRM_I915_DEBUG_GUC >>> +    if (unlikely(head != READ_ONCE(desc->head))) { >>> +        CT_ERROR(ct, "Head was modified %u != %u\n", >>> +             desc->head, ctb->head); >>> +        desc->status |= GUC_CTB_STATUS_MISMATCH; >>> +        goto corrupted; >>> +    } >>> +    if (unlikely((desc->tail | desc->head) >= size)) { >>> +        CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n", >>> +             head, tail, size); >>> +        desc->status |= GUC_CTB_STATUS_OVERFLOW; >>> +        goto corrupted; >>> +    } >>> +#else >>> +    if (unlikely((tail | ctb->head) >= size)) { >> Could just be 'head' rather than 'ctb->head'. > or drop "ctb->head" completely since this is driver owned field and > above you already have BUGON to test it > > Michal > >> John. >> >>>           CT_ERROR(ct, "Invalid offsets head=%u tail=%u (size=%u)\n", >>>                head, tail, size); >>>           desc->status |= GUC_CTB_STATUS_OVERFLOW; >>>           goto corrupted; >>>       } >>> +#endif >>>         /* tail == head condition indicates empty */ >>>       available = tail - head; >>> @@ -803,6 +832,7 @@ static int ct_read(struct intel_guc_ct *ct, struct >>> ct_incoming_msg **msg) >>>       } >>>       CT_DEBUG(ct, "received %*ph\n", 4 * len, (*msg)->msg); >>>   +    ctb->head = head; >>>       /* now update descriptor */ >>>       WRITE_ONCE(desc->head, head); >>>   diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>> b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>> index bee03794c1eb..edd1bba0445d 100644 >>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.h >>> @@ -33,6 +33,9 @@ struct intel_guc; >>>    * @desc: pointer to the buffer descriptor >>>    * @cmds: pointer to the commands buffer >>>    * @size: size of the commands buffer in dwords >>> + * @head: local shadow copy of head in dwords >>> + * @tail: local shadow copy of tail in dwords >>> + * @space: local shadow copy of space in dwords >>>    * @broken: flag to indicate if descriptor data is broken >>>    */ >>>   struct intel_guc_ct_buffer { >>> @@ -40,6 +43,9 @@ struct intel_guc_ct_buffer { >>>       struct guc_ct_buffer_desc *desc; >>>       u32 *cmds; >>>       u32 size; >>> +    u32 tail; >>> +    u32 head; >>> +    u32 space; >>>       bool broken; >>>   }; >>> 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=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_SANE_1 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 48700C07E96 for ; Tue, 6 Jul 2021 19:19:45 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 13BFA61C7A for ; Tue, 6 Jul 2021 19:19:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 13BFA61C7A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E8CC56E5A1; Tue, 6 Jul 2021 19:19:39 +0000 (UTC) Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTPS id 9499E6E59D; Tue, 6 Jul 2021 19:19:37 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6200,9189,10037"; a="206169110" X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="206169110" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 12:19:25 -0700 X-IronPort-AV: E=Sophos;i="5.83,329,1616482800"; d="scan'208";a="457182410" Received: from johnharr-mobl1.amr.corp.intel.com (HELO [10.212.151.177]) ([10.212.151.177]) by orsmga008-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Jul 2021 12:19:25 -0700 To: Michal Wajdeczko , Matthew Brost , intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org References: <20210701171550.49353-1-matthew.brost@intel.com> <20210701171550.49353-7-matthew.brost@intel.com> <3147114d-4b4b-1a42-c40b-8d8be870e633@intel.com> From: John Harrison Message-ID: Date: Tue, 6 Jul 2021 12:19:24 -0700 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-GB Subject: Re: [Intel-gfx] [PATCH 6/7] drm/i915/guc: Optimize CTB writes and reads X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Transfer-Encoding: base64 Content-Type: text/plain; charset="utf-8"; Format="flowed" Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" T24gNy82LzIwMjEgMTI6MTIsIE1pY2hhbCBXYWpkZWN6a28gd3JvdGU6Cj4gT24gMDYuMDcuMjAy MSAyMTowMCwgSm9obiBIYXJyaXNvbiB3cm90ZToKPj4gT24gNy8xLzIwMjEgMTA6MTUsIE1hdHRo ZXcgQnJvc3Qgd3JvdGU6Cj4+PiBDVEIgd3JpdGVzIGFyZSBub3cgaW4gdGhlIHBhdGggb2YgY29t bWFuZCBzdWJtaXNzaW9uIGFuZCBzaG91bGQgYmUKPj4+IG9wdGltaXplZCBmb3IgcGVyZm9ybWFu Y2UuIFJhdGhlciB0aGFuIHJlYWRpbmcgQ1RCIGRlc2NyaXB0b3IgdmFsdWVzCj4+PiAoZS5nLiBo ZWFkLCB0YWlsKSB3aGljaCBjb3VsZCByZXN1bHQgaW4gYWNjZXNzZXMgYWNyb3NzIHRoZSBQQ0ll IGJ1cywKPj4+IHN0b3JlIHNoYWRvdyBsb2NhbCBjb3BpZXMgYW5kIG9ubHkgcmVhZC93cml0ZSB0 aGUgZGVzY3JpcHRvciB2YWx1ZXMgd2hlbgo+Pj4gYWJzb2x1dGVseSBuZWNlc3NhcnkuIEFsc28g c3RvcmUgdGhlIGN1cnJlbnQgc3BhY2UgaW4gdGhlIGVhY2ggY2hhbm5lbAo+Pj4gbG9jYWxseS4K Pj4+Cj4+PiB2MjoKPj4+ICDCoCAoTWljaGVsKQo+Pj4gIMKgwqAgLSBBZGQgYWRkaXRpb25hbCBz YW5pdHkgY2hlY2tzIGZvciBoZWFkIC8gdGFpbCBwb2ludGVycwo+Pj4gIMKgwqAgLSBVc2UgR1VD X0NUQl9IRFJfTEVOIHJhdGhlciB0aGFuIG1hZ2ljIDEKPj4+Cj4+PiBTaWduZWQtb2ZmLWJ5OiBK b2huIEhhcnJpc29uIDxKb2huLkMuSGFycmlzb25ASW50ZWwuY29tPgo+Pj4gU2lnbmVkLW9mZi1i eTogTWF0dGhldyBCcm9zdCA8bWF0dGhldy5icm9zdEBpbnRlbC5jb20+Cj4+PiAtLS0KPj4+ICDC oCBkcml2ZXJzL2dwdS9kcm0vaTkxNS9ndC91Yy9pbnRlbF9ndWNfY3QuYyB8IDg4ICsrKysrKysr KysrKysrKy0tLS0tLS0tCj4+PiAgwqAgZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxf Z3VjX2N0LmggfMKgIDYgKysKPj4+ICDCoCAyIGZpbGVzIGNoYW5nZWQsIDY1IGluc2VydGlvbnMo KyksIDI5IGRlbGV0aW9ucygtKQo+Pj4KPj4+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0v aTkxNS9ndC91Yy9pbnRlbF9ndWNfY3QuYwo+Pj4gYi9kcml2ZXJzL2dwdS9kcm0vaTkxNS9ndC91 Yy9pbnRlbF9ndWNfY3QuYwo+Pj4gaW5kZXggYTljYjdiNjA4NTIwLi41YjhiNGZmNjA5ZTIgMTAw NjQ0Cj4+PiAtLS0gYS9kcml2ZXJzL2dwdS9kcm0vaTkxNS9ndC91Yy9pbnRlbF9ndWNfY3QuYwo+ Pj4gKysrIGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3VjX2N0LmMKPj4+IEBA IC0xMzAsNiArMTMwLDEwIEBAIHN0YXRpYyB2b2lkIGd1Y19jdF9idWZmZXJfZGVzY19pbml0KHN0 cnVjdAo+Pj4gZ3VjX2N0X2J1ZmZlcl9kZXNjICpkZXNjKQo+Pj4gIMKgIHN0YXRpYyB2b2lkIGd1 Y19jdF9idWZmZXJfcmVzZXQoc3RydWN0IGludGVsX2d1Y19jdF9idWZmZXIgKmN0YikKPj4+ICDC oCB7Cj4+PiAgwqDCoMKgwqDCoCBjdGItPmJyb2tlbiA9IGZhbHNlOwo+Pj4gK8KgwqDCoCBjdGIt PnRhaWwgPSAwOwo+Pj4gK8KgwqDCoCBjdGItPmhlYWQgPSAwOwo+Pj4gK8KgwqDCoCBjdGItPnNw YWNlID0gQ0lSQ19TUEFDRShjdGItPnRhaWwsIGN0Yi0+aGVhZCwgY3RiLT5zaXplKTsKPj4+ICsK Pj4+ICDCoMKgwqDCoMKgIGd1Y19jdF9idWZmZXJfZGVzY19pbml0KGN0Yi0+ZGVzYyk7Cj4+PiAg wqAgfQo+Pj4gIMKgIEBAIC0zODMsMTAgKzM4Nyw4IEBAIHN0YXRpYyBpbnQgY3Rfd3JpdGUoc3Ry dWN0IGludGVsX2d1Y19jdCAqY3QsCj4+PiAgwqAgewo+Pj4gIMKgwqDCoMKgwqAgc3RydWN0IGlu dGVsX2d1Y19jdF9idWZmZXIgKmN0YiA9ICZjdC0+Y3Ricy5zZW5kOwo+Pj4gIMKgwqDCoMKgwqAg c3RydWN0IGd1Y19jdF9idWZmZXJfZGVzYyAqZGVzYyA9IGN0Yi0+ZGVzYzsKPj4+IC3CoMKgwqAg dTMyIGhlYWQgPSBkZXNjLT5oZWFkOwo+Pj4gLcKgwqDCoCB1MzIgdGFpbCA9IGRlc2MtPnRhaWw7 Cj4+PiArwqDCoMKgIHUzMiB0YWlsID0gY3RiLT50YWlsOwo+Pj4gIMKgwqDCoMKgwqAgdTMyIHNp emUgPSBjdGItPnNpemU7Cj4+PiAtwqDCoMKgIHUzMiB1c2VkOwo+Pj4gIMKgwqDCoMKgwqAgdTMy IGhlYWRlcjsKPj4+ICDCoMKgwqDCoMKgIHUzMiBoeGc7Cj4+PiAgwqDCoMKgwqDCoCB1MzIgKmNt ZHMgPSBjdGItPmNtZHM7Cj4+PiBAQCAtMzk1LDI1ICszOTcsMjIgQEAgc3RhdGljIGludCBjdF93 cml0ZShzdHJ1Y3QgaW50ZWxfZ3VjX2N0ICpjdCwKPj4+ICDCoMKgwqDCoMKgIGlmICh1bmxpa2Vs eShkZXNjLT5zdGF0dXMpKQo+Pj4gIMKgwqDCoMKgwqDCoMKgwqDCoCBnb3RvIGNvcnJ1cHRlZDsK Pj4+ICDCoCAtwqDCoMKgIGlmICh1bmxpa2VseSgodGFpbCB8IGhlYWQpID49IHNpemUpKSB7Cj4+ PiArwqDCoMKgIEdFTV9CVUdfT04odGFpbCA+IHNpemUpOwo+Pj4gKwo+Pj4gKyNpZmRlZiBDT05G SUdfRFJNX0k5MTVfREVCVUdfR1VDCj4+PiArwqDCoMKgIGlmICh1bmxpa2VseSh0YWlsICE9IFJF QURfT05DRShkZXNjLT50YWlsKSkpIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCBDVF9FUlJPUihjdCwg IlRhaWwgd2FzIG1vZGlmaWVkICV1ICE9ICV1XG4iLAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDCoMKg wqDCoCBkZXNjLT50YWlsLCBjdGItPnRhaWwpOwo+Pj4gK8KgwqDCoMKgwqDCoMKgIGRlc2MtPnN0 YXR1cyB8PSBHVUNfQ1RCX1NUQVRVU19NSVNNQVRDSDsKPj4+ICvCoMKgwqDCoMKgwqDCoCBnb3Rv IGNvcnJ1cHRlZDsKPj4+ICvCoMKgwqAgfQo+Pj4gK8KgwqDCoCBpZiAodW5saWtlbHkoKGRlc2Mt PnRhaWwgfCBkZXNjLT5oZWFkKSA+PSBzaXplKSkgewo+Pj4gIMKgwqDCoMKgwqDCoMKgwqDCoCBD VF9FUlJPUihjdCwgIkludmFsaWQgb2Zmc2V0cyBoZWFkPSV1IHRhaWw9JXUgKHNpemU9JXUpXG4i LAo+Pj4gLcKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBoZWFkLCB0YWlsLCBzaXplKTsKPj4+ICvC oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGVzYy0+aGVhZCwgZGVzYy0+dGFpbCwgc2l6ZSk7Cj4+ PiAgwqDCoMKgwqDCoMKgwqDCoMKgIGRlc2MtPnN0YXR1cyB8PSBHVUNfQ1RCX1NUQVRVU19PVkVS RkxPVzsKPj4+ICDCoMKgwqDCoMKgwqDCoMKgwqAgZ290byBjb3JydXB0ZWQ7Cj4+PiAgwqDCoMKg wqDCoCB9Cj4+PiAtCj4+PiAtwqDCoMKgIC8qCj4+PiAtwqDCoMKgwqAgKiB0YWlsID09IGhlYWQg Y29uZGl0aW9uIGluZGljYXRlcyBlbXB0eS4gR3VDIEZXIGRvZXMgbm90IHN1cHBvcnQKPj4+IC3C oMKgwqDCoCAqIHVzaW5nIHVwIHRoZSBlbnRpcmUgYnVmZmVyIHRvIGdldCB0YWlsID09IGhlYWQg bWVhbmluZyBmdWxsLgo+Pj4gLcKgwqDCoMKgICovCj4+PiAtwqDCoMKgIGlmICh0YWlsIDwgaGVh ZCkKPj4+IC3CoMKgwqDCoMKgwqDCoCB1c2VkID0gKHNpemUgLSBoZWFkKSArIHRhaWw7Cj4+PiAt wqDCoMKgIGVsc2UKPj4+IC3CoMKgwqDCoMKgwqDCoCB1c2VkID0gdGFpbCAtIGhlYWQ7Cj4+PiAt Cj4+PiAtwqDCoMKgIC8qIG1ha2Ugc3VyZSB0aGVyZSBpcyBhIHNwYWNlIGluY2x1ZGluZyBleHRy YSBkdyBmb3IgdGhlIGZlbmNlICovCj4+PiAtwqDCoMKgIGlmICh1bmxpa2VseSh1c2VkICsgbGVu ICsgR1VDX0NUQl9IRFJfTEVOID49IHNpemUpKQo+Pj4gLcKgwqDCoMKgwqDCoMKgIHJldHVybiAt RU5PU1BDOwo+Pj4gKyNlbmRpZgo+Pj4gIMKgIMKgwqDCoMKgwqAgLyoKPj4+ICDCoMKgwqDCoMKg wqAgKiBkdzA6IENUIGhlYWRlciAoaW5jbHVkaW5nIGZlbmNlKQo+Pj4gQEAgLTQ1NCw3ICs0NTMs OSBAQCBzdGF0aWMgaW50IGN0X3dyaXRlKHN0cnVjdCBpbnRlbF9ndWNfY3QgKmN0LAo+Pj4gIMKg wqDCoMKgwqAgd3JpdGVfYmFycmllcihjdCk7Cj4+PiAgwqAgwqDCoMKgwqDCoCAvKiBub3cgdXBk YXRlIGRlc2NyaXB0b3IgKi8KPj4+ICvCoMKgwqAgY3RiLT50YWlsID0gdGFpbDsKPj4+ICDCoMKg wqDCoMKgIFdSSVRFX09OQ0UoZGVzYy0+dGFpbCwgdGFpbCk7Cj4+PiArwqDCoMKgIGN0Yi0+c3Bh Y2UgLT0gbGVuICsgR1VDX0NUQl9IRFJfTEVOOwo+Pj4gIMKgIMKgwqDCoMKgwqAgcmV0dXJuIDA7 Cj4+PiAgwqAgQEAgLTQ3MCw3ICs0NzEsNyBAQCBzdGF0aWMgaW50IGN0X3dyaXRlKHN0cnVjdCBp bnRlbF9ndWNfY3QgKmN0LAo+Pj4gIMKgwqAgKiBAcmVxOsKgwqDCoCBwb2ludGVyIHRvIHBlbmRp bmcgcmVxdWVzdAo+Pj4gIMKgwqAgKiBAc3RhdHVzOsKgwqDCoCBwbGFjZWhvbGRlciBmb3Igc3Rh dHVzCj4+PiAgwqDCoCAqCj4+PiAtICogRm9yIGVhY2ggc2VudCByZXF1ZXN0LCBHdWMgc2hhbGwg c2VuZCBiYWMgQ1QgcmVzcG9uc2UgbWVzc2FnZS4KPj4+ICsgKiBGb3IgZWFjaCBzZW50IHJlcXVl c3QsIEd1QyBzaGFsbCBzZW5kIGJhY2sgQ1QgcmVzcG9uc2UgbWVzc2FnZS4KPj4+ICDCoMKgICog T3VyIG1lc3NhZ2UgaGFuZGxlciB3aWxsIHVwZGF0ZSBzdGF0dXMgb2YgdHJhY2tlZCByZXF1ZXN0 IG9uY2UKPj4+ICDCoMKgICogcmVzcG9uc2UgbWVzc2FnZSB3aXRoIGdpdmVuIGZlbmNlIGlzIHJl Y2VpdmVkLiBXYWl0IGhlcmUgYW5kCj4+PiAgwqDCoCAqIGNoZWNrIGZvciB2YWxpZCByZXNwb25z ZSBzdGF0dXMgdmFsdWUuCj4+PiBAQCAtNTI2LDI0ICs1MjcsMzUgQEAgc3RhdGljIGlubGluZSBi b29sIGN0X2RlYWRsb2NrZWQoc3RydWN0Cj4+PiBpbnRlbF9ndWNfY3QgKmN0KQo+Pj4gIMKgwqDC oMKgwqAgcmV0dXJuIHJldDsKPj4+ICDCoCB9Cj4+PiAgwqAgLXN0YXRpYyBpbmxpbmUgYm9vbCBo MmdfaGFzX3Jvb20oc3RydWN0IGludGVsX2d1Y19jdF9idWZmZXIgKmN0YiwKPj4+IHUzMiBsZW5f ZHcpCj4+PiArc3RhdGljIGlubGluZSBib29sIGgyZ19oYXNfcm9vbShzdHJ1Y3QgaW50ZWxfZ3Vj X2N0ICpjdCwgdTMyIGxlbl9kdykKPj4+ICDCoCB7Cj4+PiAtwqDCoMKgIHN0cnVjdCBndWNfY3Rf YnVmZmVyX2Rlc2MgKmRlc2MgPSBjdGItPmRlc2M7Cj4+PiAtwqDCoMKgIHUzMiBoZWFkID0gUkVB RF9PTkNFKGRlc2MtPmhlYWQpOwo+Pj4gK8KgwqDCoCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZl ciAqY3RiID0gJmN0LT5jdGJzLnNlbmQ7Cj4+PiArwqDCoMKgIHUzMiBoZWFkOwo+Pj4gIMKgwqDC oMKgwqAgdTMyIHNwYWNlOwo+Pj4gIMKgIC3CoMKgwqAgc3BhY2UgPSBDSVJDX1NQQUNFKGRlc2Mt PnRhaWwsIGhlYWQsIGN0Yi0+c2l6ZSk7Cj4+PiArwqDCoMKgIGlmIChjdGItPnNwYWNlID49IGxl bl9kdykKPj4+ICvCoMKgwqDCoMKgwqDCoCByZXR1cm4gdHJ1ZTsKPj4+ICsKPj4+ICvCoMKgwqAg aGVhZCA9IFJFQURfT05DRShjdGItPmRlc2MtPmhlYWQpOwo+Pj4gK8KgwqDCoCBpZiAodW5saWtl bHkoaGVhZCA+IGN0Yi0+c2l6ZSkpIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCBDVF9FUlJPUihjdCwg IkNvcnJ1cHRlZCBkZXNjcmlwdG9yIGhlYWQ9JXUgdGFpbD0ldSBzaXplPSV1XG4iLAo+Pj4gK8Kg wqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjdGItPmRlc2MtPmhlYWQsIGN0Yi0+ZGVzYy0+dGFpbCwg Y3RiLT5zaXplKTsKPj4+ICvCoMKgwqDCoMKgwqDCoCBjdGItPmRlc2MtPnN0YXR1cyB8PSBHVUNf Q1RCX1NUQVRVU19PVkVSRkxPVzsKPj4+ICvCoMKgwqDCoMKgwqDCoCBjdGItPmJyb2tlbiA9IHRy dWU7Cj4+PiArwqDCoMKgwqDCoMKgwqAgcmV0dXJuIGZhbHNlOwo+Pj4gK8KgwqDCoCB9Cj4+PiAr Cj4+PiArwqDCoMKgIHNwYWNlID0gQ0lSQ19TUEFDRShjdGItPnRhaWwsIGhlYWQsIGN0Yi0+c2l6 ZSk7Cj4+PiArwqDCoMKgIGN0Yi0+c3BhY2UgPSBzcGFjZTsKPj4+ICDCoCDCoMKgwqDCoMKgIHJl dHVybiBzcGFjZSA+PSBsZW5fZHc7Cj4+PiAgwqAgfQo+Pj4gIMKgIMKgIHN0YXRpYyBpbnQgaGFz X3Jvb21fbmIoc3RydWN0IGludGVsX2d1Y19jdCAqY3QsIHUzMiBsZW5fZHcpCj4+PiAgwqAgewo+ Pj4gLcKgwqDCoCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciAqY3RiID0gJmN0LT5jdGJzLnNl bmQ7Cj4+PiAtCj4+PiAgwqDCoMKgwqDCoCBsb2NrZGVwX2Fzc2VydF9oZWxkKCZjdC0+Y3Ricy5z ZW5kLmxvY2spOwo+Pj4gIMKgIC3CoMKgwqAgaWYgKHVubGlrZWx5KCFoMmdfaGFzX3Jvb20oY3Ri LCBsZW5fZHcpKSkgewo+Pj4gK8KgwqDCoCBpZiAodW5saWtlbHkoIWgyZ19oYXNfcm9vbShjdCwg bGVuX2R3KSkpIHsKPj4+ICDCoMKgwqDCoMKgwqDCoMKgwqAgaWYgKGN0LT5zdGFsbF90aW1lID09 IEtUSU1FX01BWCkKPj4+ICDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBjdC0+c3RhbGxfdGlt ZSA9IGt0aW1lX2dldCgpOwo+Pj4gIMKgIEBAIC02MTMsNyArNjI1LDcgQEAgc3RhdGljIGludCBj dF9zZW5kKHN0cnVjdCBpbnRlbF9ndWNfY3QgKmN0LAo+Pj4gIMKgwqDCoMKgwqDCoCAqLwo+Pj4g IMKgIHJldHJ5Ogo+Pj4gIMKgwqDCoMKgwqAgc3Bpbl9sb2NrX2lycXNhdmUoJmN0Yi0+bG9jaywg ZmxhZ3MpOwo+Pj4gLcKgwqDCoCBpZiAodW5saWtlbHkoIWgyZ19oYXNfcm9vbShjdGIsIGxlbiAr IEdVQ19DVEJfSERSX0xFTikpKSB7Cj4+PiArwqDCoMKgIGlmICh1bmxpa2VseSghaDJnX2hhc19y b29tKGN0LCBsZW4gKyBHVUNfQ1RCX0hEUl9MRU4pKSkgewo+Pj4gIMKgwqDCoMKgwqDCoMKgwqDC oCBpZiAoY3QtPnN0YWxsX3RpbWUgPT0gS1RJTUVfTUFYKQo+Pj4gIMKgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoMKgIGN0LT5zdGFsbF90aW1lID0ga3RpbWVfZ2V0KCk7Cj4+PiAgwqDCoMKgwqDCoMKg wqDCoMKgIHNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmN0Yi0+bG9jaywgZmxhZ3MpOwo+Pj4gQEAg LTczMyw3ICs3NDUsNyBAQCBzdGF0aWMgaW50IGN0X3JlYWQoc3RydWN0IGludGVsX2d1Y19jdCAq Y3QsIHN0cnVjdAo+Pj4gY3RfaW5jb21pbmdfbXNnICoqbXNnKQo+Pj4gIMKgIHsKPj4+ICDCoMKg wqDCoMKgIHN0cnVjdCBpbnRlbF9ndWNfY3RfYnVmZmVyICpjdGIgPSAmY3QtPmN0YnMucmVjdjsK Pj4+ICDCoMKgwqDCoMKgIHN0cnVjdCBndWNfY3RfYnVmZmVyX2Rlc2MgKmRlc2MgPSBjdGItPmRl c2M7Cj4+PiAtwqDCoMKgIHUzMiBoZWFkID0gZGVzYy0+aGVhZDsKPj4+ICvCoMKgwqAgdTMyIGhl YWQgPSBjdGItPmhlYWQ7Cj4+PiAgwqDCoMKgwqDCoCB1MzIgdGFpbCA9IGRlc2MtPnRhaWw7Cj4+ PiAgwqDCoMKgwqDCoCB1MzIgc2l6ZSA9IGN0Yi0+c2l6ZTsKPj4+ICDCoMKgwqDCoMKgIHUzMiAq Y21kcyA9IGN0Yi0+Y21kczsKPj4+IEBAIC03NDgsMTIgKzc2MCwyOSBAQCBzdGF0aWMgaW50IGN0 X3JlYWQoc3RydWN0IGludGVsX2d1Y19jdCAqY3QsCj4+PiBzdHJ1Y3QgY3RfaW5jb21pbmdfbXNn ICoqbXNnKQo+Pj4gIMKgwqDCoMKgwqAgaWYgKHVubGlrZWx5KGRlc2MtPnN0YXR1cykpCj4+PiAg wqDCoMKgwqDCoMKgwqDCoMKgIGdvdG8gY29ycnVwdGVkOwo+Pj4gIMKgIC3CoMKgwqAgaWYgKHVu bGlrZWx5KCh0YWlsIHwgaGVhZCkgPj0gc2l6ZSkpIHsKPj4+ICvCoMKgwqAgR0VNX0JVR19PTiho ZWFkID4gc2l6ZSk7Cj4+IElzIHRoZSBCVUdfT04gbmVjZXNzYXJ5IGdpdmVuIHRoYXQgYm90aCBv cHRpb25zIGJlbG93IGRvIHRoZSBzYW1lIGNoZWNrCj4+IGJ1dCBhcyBhIGNvcnJ1cHRlZCBidWZm ZXIgdGVzdCAod2l0aCBzdWJzZXF1ZW50IHJlY292ZXJ5IGJ5IEdUIHJlc2V0PykKPj4gcmF0aGVy IHRoYW4ga2lsbGluZyB0aGUgZHJpdmVyLgo+ICJoZWFkIiBhbmQgInNpemUiIGFyZSBub3cgZnVs bHkgb3duZWQgYnkgdGhlIGRyaXZlci4KPiBCVUdPTiBoZXJlIGlzIHRvIG1ha2Ugc3VyZSBkcml2 ZXIgaXMgY29kZWQgY29ycmVjdGx5LgpUaGUgcG9pbnQgaXMgdGhhdCBib3RoIHNpZGVzIG9mIHRo ZSAjaWYgYmVsb3cgYWxzbyB2YWxpZGF0ZSBoZWFkLiBTbyAKZmlyc3QgdGhlcmUgaXMgYSBCVUdf T04sIHRoZW4gdGhlcmUgaXMgdGhlIHNhbWUgdGVzdCBidXQgd2l0aG91dCBibG93aW5nIAp0aGUg ZHJpdmVyIGFwYXJ0LiBPbmUgb3IgdGhlIG90aGVyIGlzIG5vdCByZXF1aXJlZC4gTXkgdm90ZSB3 b3VsZCBiZSB0byAKa2VlcCB0aGUgcmVjb3ZlcmFibGUgdGVzdCByYXRoZXIgdGhhbiB0aGUgQlVH X09OLgoKSm9obi4KCj4KPj4+ICsKPj4+ICsjaWZkZWYgQ09ORklHX0RSTV9JOTE1X0RFQlVHX0dV Qwo+Pj4gK8KgwqDCoCBpZiAodW5saWtlbHkoaGVhZCAhPSBSRUFEX09OQ0UoZGVzYy0+aGVhZCkp KSB7Cj4+PiArwqDCoMKgwqDCoMKgwqAgQ1RfRVJST1IoY3QsICJIZWFkIHdhcyBtb2RpZmllZCAl dSAhPSAldVxuIiwKPj4+ICvCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqAgZGVzYy0+aGVhZCwgY3Ri LT5oZWFkKTsKPj4+ICvCoMKgwqDCoMKgwqDCoCBkZXNjLT5zdGF0dXMgfD0gR1VDX0NUQl9TVEFU VVNfTUlTTUFUQ0g7Cj4+PiArwqDCoMKgwqDCoMKgwqAgZ290byBjb3JydXB0ZWQ7Cj4+PiArwqDC oMKgIH0KPj4+ICvCoMKgwqAgaWYgKHVubGlrZWx5KChkZXNjLT50YWlsIHwgZGVzYy0+aGVhZCkg Pj0gc2l6ZSkpIHsKPj4+ICvCoMKgwqDCoMKgwqDCoCBDVF9FUlJPUihjdCwgIkludmFsaWQgb2Zm c2V0cyBoZWFkPSV1IHRhaWw9JXUgKHNpemU9JXUpXG4iLAo+Pj4gK8KgwqDCoMKgwqDCoMKgwqDC oMKgwqDCoCBoZWFkLCB0YWlsLCBzaXplKTsKPj4+ICvCoMKgwqDCoMKgwqDCoCBkZXNjLT5zdGF0 dXMgfD0gR1VDX0NUQl9TVEFUVVNfT1ZFUkZMT1c7Cj4+PiArwqDCoMKgwqDCoMKgwqAgZ290byBj b3JydXB0ZWQ7Cj4+PiArwqDCoMKgIH0KPj4+ICsjZWxzZQo+Pj4gK8KgwqDCoCBpZiAodW5saWtl bHkoKHRhaWwgfCBjdGItPmhlYWQpID49IHNpemUpKSB7Cj4+IENvdWxkIGp1c3QgYmUgJ2hlYWQn IHJhdGhlciB0aGFuICdjdGItPmhlYWQnLgo+IG9yIGRyb3AgImN0Yi0+aGVhZCIgY29tcGxldGVs eSBzaW5jZSB0aGlzIGlzIGRyaXZlciBvd25lZCBmaWVsZCBhbmQKPiBhYm92ZSB5b3UgYWxyZWFk eSBoYXZlIEJVR09OIHRvIHRlc3QgaXQKPgo+IE1pY2hhbAo+Cj4+IEpvaG4uCj4+Cj4+PiAgwqDC oMKgwqDCoMKgwqDCoMKgIENUX0VSUk9SKGN0LCAiSW52YWxpZCBvZmZzZXRzIGhlYWQ9JXUgdGFp bD0ldSAoc2l6ZT0ldSlcbiIsCj4+PiAgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBoZWFk LCB0YWlsLCBzaXplKTsKPj4+ICDCoMKgwqDCoMKgwqDCoMKgwqAgZGVzYy0+c3RhdHVzIHw9IEdV Q19DVEJfU1RBVFVTX09WRVJGTE9XOwo+Pj4gIMKgwqDCoMKgwqDCoMKgwqDCoCBnb3RvIGNvcnJ1 cHRlZDsKPj4+ICDCoMKgwqDCoMKgIH0KPj4+ICsjZW5kaWYKPj4+ICDCoCDCoMKgwqDCoMKgIC8q IHRhaWwgPT0gaGVhZCBjb25kaXRpb24gaW5kaWNhdGVzIGVtcHR5ICovCj4+PiAgwqDCoMKgwqDC oCBhdmFpbGFibGUgPSB0YWlsIC0gaGVhZDsKPj4+IEBAIC04MDMsNiArODMyLDcgQEAgc3RhdGlj IGludCBjdF9yZWFkKHN0cnVjdCBpbnRlbF9ndWNfY3QgKmN0LCBzdHJ1Y3QKPj4+IGN0X2luY29t aW5nX21zZyAqKm1zZykKPj4+ICDCoMKgwqDCoMKgIH0KPj4+ICDCoMKgwqDCoMKgIENUX0RFQlVH KGN0LCAicmVjZWl2ZWQgJSpwaFxuIiwgNCAqIGxlbiwgKCptc2cpLT5tc2cpOwo+Pj4gIMKgICvC oMKgwqAgY3RiLT5oZWFkID0gaGVhZDsKPj4+ICDCoMKgwqDCoMKgIC8qIG5vdyB1cGRhdGUgZGVz Y3JpcHRvciAqLwo+Pj4gIMKgwqDCoMKgwqAgV1JJVEVfT05DRShkZXNjLT5oZWFkLCBoZWFkKTsK Pj4+ICDCoCBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3Vj X2N0LmgKPj4+IGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3VjX2N0LmgKPj4+ IGluZGV4IGJlZTAzNzk0YzFlYi4uZWRkMWJiYTA0NDVkIDEwMDY0NAo+Pj4gLS0tIGEvZHJpdmVy cy9ncHUvZHJtL2k5MTUvZ3QvdWMvaW50ZWxfZ3VjX2N0LmgKPj4+ICsrKyBiL2RyaXZlcnMvZ3B1 L2RybS9pOTE1L2d0L3VjL2ludGVsX2d1Y19jdC5oCj4+PiBAQCAtMzMsNiArMzMsOSBAQCBzdHJ1 Y3QgaW50ZWxfZ3VjOwo+Pj4gIMKgwqAgKiBAZGVzYzogcG9pbnRlciB0byB0aGUgYnVmZmVyIGRl c2NyaXB0b3IKPj4+ICDCoMKgICogQGNtZHM6IHBvaW50ZXIgdG8gdGhlIGNvbW1hbmRzIGJ1ZmZl cgo+Pj4gIMKgwqAgKiBAc2l6ZTogc2l6ZSBvZiB0aGUgY29tbWFuZHMgYnVmZmVyIGluIGR3b3Jk cwo+Pj4gKyAqIEBoZWFkOiBsb2NhbCBzaGFkb3cgY29weSBvZiBoZWFkIGluIGR3b3Jkcwo+Pj4g KyAqIEB0YWlsOiBsb2NhbCBzaGFkb3cgY29weSBvZiB0YWlsIGluIGR3b3Jkcwo+Pj4gKyAqIEBz cGFjZTogbG9jYWwgc2hhZG93IGNvcHkgb2Ygc3BhY2UgaW4gZHdvcmRzCj4+PiAgwqDCoCAqIEBi cm9rZW46IGZsYWcgdG8gaW5kaWNhdGUgaWYgZGVzY3JpcHRvciBkYXRhIGlzIGJyb2tlbgo+Pj4g IMKgwqAgKi8KPj4+ICDCoCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciB7Cj4+PiBAQCAtNDAs NiArNDMsOSBAQCBzdHJ1Y3QgaW50ZWxfZ3VjX2N0X2J1ZmZlciB7Cj4+PiAgwqDCoMKgwqDCoCBz dHJ1Y3QgZ3VjX2N0X2J1ZmZlcl9kZXNjICpkZXNjOwo+Pj4gIMKgwqDCoMKgwqAgdTMyICpjbWRz Owo+Pj4gIMKgwqDCoMKgwqAgdTMyIHNpemU7Cj4+PiArwqDCoMKgIHUzMiB0YWlsOwo+Pj4gK8Kg wqDCoCB1MzIgaGVhZDsKPj4+ICvCoMKgwqAgdTMyIHNwYWNlOwo+Pj4gIMKgwqDCoMKgwqAgYm9v bCBicm9rZW47Cj4+PiAgwqAgfTsKPj4+ICAgIAoKX19fX19fX19fX19fX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX18KSW50ZWwtZ2Z4IG1haWxpbmcgbGlzdApJbnRlbC1nZnhAbGlz dHMuZnJlZWRlc2t0b3Aub3JnCmh0dHBzOi8vbGlzdHMuZnJlZWRlc2t0b3Aub3JnL21haWxtYW4v bGlzdGluZm8vaW50ZWwtZ2Z4Cg==