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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,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 83B77C49361 for ; Wed, 16 Jun 2021 14:53:35 +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 4AA8161075 for ; Wed, 16 Jun 2021 14:53:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4AA8161075 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 7747F89BB3; Wed, 16 Jun 2021 14:53:34 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0268C89BB3; Wed, 16 Jun 2021 14:53:33 +0000 (UTC) IronPort-SDR: gpfr/nXHUI/IUn/8ZGCCb08Genb6szVvOX0MNv+mzMJHp1CjGvQjlZOCemc0PtvXmsxZQrVIBT gLhIp674pYZQ== X-IronPort-AV: E=McAfee;i="6200,9189,10016"; a="270039020" X-IronPort-AV: E=Sophos;i="5.83,278,1616482800"; d="scan'208";a="270039020" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jun 2021 07:53:33 -0700 IronPort-SDR: 129lPH1nsKZbZnrTBm39GYBeBsEo2tHfv//fCkAN8b+edxldWl8cqMHRiQdy3i8WTbtOh/o8pf DHJ1jy0GQOMQ== X-IronPort-AV: E=Sophos;i="5.83,278,1616482800"; d="scan'208";a="442903082" Received: from mrapopor-mobl.ger.corp.intel.com (HELO mwauld-desk1.intel.com) ([10.213.236.122]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jun 2021 07:53:32 -0700 From: Matthew Auld To: intel-gfx@lists.freedesktop.org Subject: [PATCH v4 2/7] drm/i915/ttm: add i915_sg_from_buddy_resource Date: Wed, 16 Jun 2021 15:52:54 +0100 Message-Id: <20210616145259.357146-2-matthew.auld@intel.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210616145259.357146-1-matthew.auld@intel.com> References: <20210616145259.357146-1-matthew.auld@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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: , Cc: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" We need to be able to build an sg table from our list of buddy blocks, so that we can later plug this into our ttm backend, and replace our use of the range manager. Signed-off-by: Matthew Auld Cc: Thomas Hellström Reviewed-by: Thomas Hellström --- drivers/gpu/drm/i915/i915_scatterlist.c | 80 +++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_scatterlist.h | 5 ++ 2 files changed, 85 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_scatterlist.c b/drivers/gpu/drm/i915/i915_scatterlist.c index 69e9e6c3135e..4a6712dca838 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.c +++ b/drivers/gpu/drm/i915/i915_scatterlist.c @@ -6,6 +6,9 @@ #include "i915_scatterlist.h" +#include "i915_buddy.h" +#include "i915_ttm_buddy_manager.h" + #include #include @@ -104,6 +107,83 @@ struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node, return st; } +/** + * i915_sg_from_buddy_resource - Create an sg_table from a struct + * i915_buddy_block list + * @res: The struct i915_ttm_buddy_resource. + * @region_start: An offset to add to the dma addresses of the sg list. + * + * Create a struct sg_table, initializing it from struct i915_buddy_block list, + * taking a maximum segment length into account, splitting into segments + * if necessary. + * + * Return: A pointer to a kmalloced struct sg_table on success, negative + * error code cast to an error pointer on failure. + */ +struct sg_table *i915_sg_from_buddy_resource(struct ttm_resource *res, + u64 region_start) +{ + struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); + const u64 size = res->num_pages << PAGE_SHIFT; + const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE); + struct i915_buddy_mm *mm = bman_res->mm; + struct list_head *blocks = &bman_res->blocks; + struct i915_buddy_block *block; + struct scatterlist *sg; + struct sg_table *st; + resource_size_t prev_end; + + GEM_BUG_ON(list_empty(blocks)); + + st = kmalloc(sizeof(*st), GFP_KERNEL); + if (!st) + return ERR_PTR(-ENOMEM); + + if (sg_alloc_table(st, res->num_pages, GFP_KERNEL)) { + kfree(st); + return ERR_PTR(-ENOMEM); + } + + sg = st->sgl; + st->nents = 0; + prev_end = (resource_size_t)-1; + + list_for_each_entry(block, blocks, link) { + u64 block_size, offset; + + block_size = min_t(u64, size, i915_buddy_block_size(mm, block)); + offset = i915_buddy_block_offset(block); + + while (block_size) { + u64 len; + + if (offset != prev_end || sg->length >= max_segment) { + if (st->nents) + sg = __sg_next(sg); + + sg_dma_address(sg) = region_start + offset; + sg_dma_len(sg) = 0; + sg->length = 0; + st->nents++; + } + + len = min(block_size, max_segment - sg->length); + sg->length += len; + sg_dma_len(sg) += len; + + offset += len; + block_size -= len; + + prev_end = offset; + } + } + + sg_mark_end(sg); + i915_sg_trim(st); + + return st; +} + #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #include "selftests/scatterlist.c" #endif diff --git a/drivers/gpu/drm/i915/i915_scatterlist.h b/drivers/gpu/drm/i915/i915_scatterlist.h index 5acca45ea981..b8bd5925b03f 100644 --- a/drivers/gpu/drm/i915/i915_scatterlist.h +++ b/drivers/gpu/drm/i915/i915_scatterlist.h @@ -14,6 +14,7 @@ #include "i915_gem.h" struct drm_mm_node; +struct ttm_resource; /* * Optimised SGL iterator for GEM objects @@ -145,4 +146,8 @@ bool i915_sg_trim(struct sg_table *orig_st); struct sg_table *i915_sg_from_mm_node(const struct drm_mm_node *node, u64 region_start); + +struct sg_table *i915_sg_from_buddy_resource(struct ttm_resource *res, + u64 region_start); + #endif -- 2.26.3 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=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,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 8AD44C48BE8 for ; Wed, 16 Jun 2021 14:53: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 58E816105A for ; Wed, 16 Jun 2021 14:53:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 58E816105A 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 7112F89C54; Wed, 16 Jun 2021 14:53:35 +0000 (UTC) Received: from mga07.intel.com (mga07.intel.com [134.134.136.100]) by gabe.freedesktop.org (Postfix) with ESMTPS id 0268C89BB3; Wed, 16 Jun 2021 14:53:33 +0000 (UTC) IronPort-SDR: gpfr/nXHUI/IUn/8ZGCCb08Genb6szVvOX0MNv+mzMJHp1CjGvQjlZOCemc0PtvXmsxZQrVIBT gLhIp674pYZQ== X-IronPort-AV: E=McAfee;i="6200,9189,10016"; a="270039020" X-IronPort-AV: E=Sophos;i="5.83,278,1616482800"; d="scan'208";a="270039020" Received: from orsmga007.jf.intel.com ([10.7.209.58]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jun 2021 07:53:33 -0700 IronPort-SDR: 129lPH1nsKZbZnrTBm39GYBeBsEo2tHfv//fCkAN8b+edxldWl8cqMHRiQdy3i8WTbtOh/o8pf DHJ1jy0GQOMQ== X-IronPort-AV: E=Sophos;i="5.83,278,1616482800"; d="scan'208";a="442903082" Received: from mrapopor-mobl.ger.corp.intel.com (HELO mwauld-desk1.intel.com) ([10.213.236.122]) by orsmga007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jun 2021 07:53:32 -0700 From: Matthew Auld To: intel-gfx@lists.freedesktop.org Date: Wed, 16 Jun 2021 15:52:54 +0100 Message-Id: <20210616145259.357146-2-matthew.auld@intel.com> X-Mailer: git-send-email 2.26.3 In-Reply-To: <20210616145259.357146-1-matthew.auld@intel.com> References: <20210616145259.357146-1-matthew.auld@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v4 2/7] drm/i915/ttm: add i915_sg_from_buddy_resource 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: , Cc: =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , dri-devel@lists.freedesktop.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" V2UgbmVlZCB0byBiZSBhYmxlIHRvIGJ1aWxkIGFuIHNnIHRhYmxlIGZyb20gb3VyIGxpc3Qgb2Yg YnVkZHkgYmxvY2tzLApzbyB0aGF0IHdlIGNhbiBsYXRlciBwbHVnIHRoaXMgaW50byBvdXIgdHRt IGJhY2tlbmQsIGFuZCByZXBsYWNlIG91ciB1c2UKb2YgdGhlIHJhbmdlIG1hbmFnZXIuCgpTaWdu ZWQtb2ZmLWJ5OiBNYXR0aGV3IEF1bGQgPG1hdHRoZXcuYXVsZEBpbnRlbC5jb20+CkNjOiBUaG9t YXMgSGVsbHN0csO2bSA8dGhvbWFzLmhlbGxzdHJvbUBsaW51eC5pbnRlbC5jb20+ClJldmlld2Vk LWJ5OiBUaG9tYXMgSGVsbHN0csO2bSA8dGhvbWFzLmhlbGxzdHJvbUBsaW51eC5pbnRlbC5jb20+ Ci0tLQogZHJpdmVycy9ncHUvZHJtL2k5MTUvaTkxNV9zY2F0dGVybGlzdC5jIHwgODAgKysrKysr KysrKysrKysrKysrKysrKysrKwogZHJpdmVycy9ncHUvZHJtL2k5MTUvaTkxNV9zY2F0dGVybGlz dC5oIHwgIDUgKysKIDIgZmlsZXMgY2hhbmdlZCwgODUgaW5zZXJ0aW9ucygrKQoKZGlmZiAtLWdp dCBhL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2k5MTVfc2NhdHRlcmxpc3QuYyBiL2RyaXZlcnMvZ3B1 L2RybS9pOTE1L2k5MTVfc2NhdHRlcmxpc3QuYwppbmRleCA2OWU5ZTZjMzEzNWUuLjRhNjcxMmRj YTgzOCAxMDA2NDQKLS0tIGEvZHJpdmVycy9ncHUvZHJtL2k5MTUvaTkxNV9zY2F0dGVybGlzdC5j CisrKyBiL2RyaXZlcnMvZ3B1L2RybS9pOTE1L2k5MTVfc2NhdHRlcmxpc3QuYwpAQCAtNiw2ICs2 LDkgQEAKIAogI2luY2x1ZGUgImk5MTVfc2NhdHRlcmxpc3QuaCIKIAorI2luY2x1ZGUgImk5MTVf YnVkZHkuaCIKKyNpbmNsdWRlICJpOTE1X3R0bV9idWRkeV9tYW5hZ2VyLmgiCisKICNpbmNsdWRl IDxkcm0vZHJtX21tLmg+CiAKICNpbmNsdWRlIDxsaW51eC9zbGFiLmg+CkBAIC0xMDQsNiArMTA3 LDgzIEBAIHN0cnVjdCBzZ190YWJsZSAqaTkxNV9zZ19mcm9tX21tX25vZGUoY29uc3Qgc3RydWN0 IGRybV9tbV9ub2RlICpub2RlLAogCXJldHVybiBzdDsKIH0KIAorLyoqCisgKiBpOTE1X3NnX2Zy b21fYnVkZHlfcmVzb3VyY2UgLSBDcmVhdGUgYW4gc2dfdGFibGUgZnJvbSBhIHN0cnVjdAorICog aTkxNV9idWRkeV9ibG9jayBsaXN0CisgKiBAcmVzOiBUaGUgc3RydWN0IGk5MTVfdHRtX2J1ZGR5 X3Jlc291cmNlLgorICogQHJlZ2lvbl9zdGFydDogQW4gb2Zmc2V0IHRvIGFkZCB0byB0aGUgZG1h IGFkZHJlc3NlcyBvZiB0aGUgc2cgbGlzdC4KKyAqCisgKiBDcmVhdGUgYSBzdHJ1Y3Qgc2dfdGFi bGUsIGluaXRpYWxpemluZyBpdCBmcm9tIHN0cnVjdCBpOTE1X2J1ZGR5X2Jsb2NrIGxpc3QsCisg KiB0YWtpbmcgYSBtYXhpbXVtIHNlZ21lbnQgbGVuZ3RoIGludG8gYWNjb3VudCwgc3BsaXR0aW5n IGludG8gc2VnbWVudHMKKyAqIGlmIG5lY2Vzc2FyeS4KKyAqCisgKiBSZXR1cm46IEEgcG9pbnRl ciB0byBhIGttYWxsb2NlZCBzdHJ1Y3Qgc2dfdGFibGUgb24gc3VjY2VzcywgbmVnYXRpdmUKKyAq IGVycm9yIGNvZGUgY2FzdCB0byBhbiBlcnJvciBwb2ludGVyIG9uIGZhaWx1cmUuCisgKi8KK3N0 cnVjdCBzZ190YWJsZSAqaTkxNV9zZ19mcm9tX2J1ZGR5X3Jlc291cmNlKHN0cnVjdCB0dG1fcmVz b3VyY2UgKnJlcywKKwkJCQkJICAgICB1NjQgcmVnaW9uX3N0YXJ0KQoreworCXN0cnVjdCBpOTE1 X3R0bV9idWRkeV9yZXNvdXJjZSAqYm1hbl9yZXMgPSB0b190dG1fYnVkZHlfcmVzb3VyY2UocmVz KTsKKwljb25zdCB1NjQgc2l6ZSA9IHJlcy0+bnVtX3BhZ2VzIDw8IFBBR0VfU0hJRlQ7CisJY29u c3QgdTY0IG1heF9zZWdtZW50ID0gcm91bmRkb3duKFVJTlRfTUFYLCBQQUdFX1NJWkUpOworCXN0 cnVjdCBpOTE1X2J1ZGR5X21tICptbSA9IGJtYW5fcmVzLT5tbTsKKwlzdHJ1Y3QgbGlzdF9oZWFk ICpibG9ja3MgPSAmYm1hbl9yZXMtPmJsb2NrczsKKwlzdHJ1Y3QgaTkxNV9idWRkeV9ibG9jayAq YmxvY2s7CisJc3RydWN0IHNjYXR0ZXJsaXN0ICpzZzsKKwlzdHJ1Y3Qgc2dfdGFibGUgKnN0Owor CXJlc291cmNlX3NpemVfdCBwcmV2X2VuZDsKKworCUdFTV9CVUdfT04obGlzdF9lbXB0eShibG9j a3MpKTsKKworCXN0ID0ga21hbGxvYyhzaXplb2YoKnN0KSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFz dCkKKwkJcmV0dXJuIEVSUl9QVFIoLUVOT01FTSk7CisKKwlpZiAoc2dfYWxsb2NfdGFibGUoc3Qs IHJlcy0+bnVtX3BhZ2VzLCBHRlBfS0VSTkVMKSkgeworCQlrZnJlZShzdCk7CisJCXJldHVybiBF UlJfUFRSKC1FTk9NRU0pOworCX0KKworCXNnID0gc3QtPnNnbDsKKwlzdC0+bmVudHMgPSAwOwor CXByZXZfZW5kID0gKHJlc291cmNlX3NpemVfdCktMTsKKworCWxpc3RfZm9yX2VhY2hfZW50cnko YmxvY2ssIGJsb2NrcywgbGluaykgeworCQl1NjQgYmxvY2tfc2l6ZSwgb2Zmc2V0OworCisJCWJs b2NrX3NpemUgPSBtaW5fdCh1NjQsIHNpemUsIGk5MTVfYnVkZHlfYmxvY2tfc2l6ZShtbSwgYmxv Y2spKTsKKwkJb2Zmc2V0ID0gaTkxNV9idWRkeV9ibG9ja19vZmZzZXQoYmxvY2spOworCisJCXdo aWxlIChibG9ja19zaXplKSB7CisJCQl1NjQgbGVuOworCisJCQlpZiAob2Zmc2V0ICE9IHByZXZf ZW5kIHx8IHNnLT5sZW5ndGggPj0gbWF4X3NlZ21lbnQpIHsKKwkJCQlpZiAoc3QtPm5lbnRzKQor CQkJCQlzZyA9IF9fc2dfbmV4dChzZyk7CisKKwkJCQlzZ19kbWFfYWRkcmVzcyhzZykgPSByZWdp b25fc3RhcnQgKyBvZmZzZXQ7CisJCQkJc2dfZG1hX2xlbihzZykgPSAwOworCQkJCXNnLT5sZW5n dGggPSAwOworCQkJCXN0LT5uZW50cysrOworCQkJfQorCisJCQlsZW4gPSBtaW4oYmxvY2tfc2l6 ZSwgbWF4X3NlZ21lbnQgLSBzZy0+bGVuZ3RoKTsKKwkJCXNnLT5sZW5ndGggKz0gbGVuOworCQkJ c2dfZG1hX2xlbihzZykgKz0gbGVuOworCisJCQlvZmZzZXQgKz0gbGVuOworCQkJYmxvY2tfc2l6 ZSAtPSBsZW47CisKKwkJCXByZXZfZW5kID0gb2Zmc2V0OworCQl9CisJfQorCisJc2dfbWFya19l bmQoc2cpOworCWk5MTVfc2dfdHJpbShzdCk7CisKKwlyZXR1cm4gc3Q7Cit9CisKICNpZiBJU19F TkFCTEVEKENPTkZJR19EUk1fSTkxNV9TRUxGVEVTVCkKICNpbmNsdWRlICJzZWxmdGVzdHMvc2Nh dHRlcmxpc3QuYyIKICNlbmRpZgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL2k5MTUvaTkx NV9zY2F0dGVybGlzdC5oIGIvZHJpdmVycy9ncHUvZHJtL2k5MTUvaTkxNV9zY2F0dGVybGlzdC5o CmluZGV4IDVhY2NhNDVlYTk4MS4uYjhiZDU5MjViMDNmIDEwMDY0NAotLS0gYS9kcml2ZXJzL2dw dS9kcm0vaTkxNS9pOTE1X3NjYXR0ZXJsaXN0LmgKKysrIGIvZHJpdmVycy9ncHUvZHJtL2k5MTUv aTkxNV9zY2F0dGVybGlzdC5oCkBAIC0xNCw2ICsxNCw3IEBACiAjaW5jbHVkZSAiaTkxNV9nZW0u aCIKIAogc3RydWN0IGRybV9tbV9ub2RlOworc3RydWN0IHR0bV9yZXNvdXJjZTsKIAogLyoKICAq IE9wdGltaXNlZCBTR0wgaXRlcmF0b3IgZm9yIEdFTSBvYmplY3RzCkBAIC0xNDUsNCArMTQ2LDgg QEAgYm9vbCBpOTE1X3NnX3RyaW0oc3RydWN0IHNnX3RhYmxlICpvcmlnX3N0KTsKIAogc3RydWN0 IHNnX3RhYmxlICppOTE1X3NnX2Zyb21fbW1fbm9kZShjb25zdCBzdHJ1Y3QgZHJtX21tX25vZGUg Km5vZGUsCiAJCQkJICAgICAgdTY0IHJlZ2lvbl9zdGFydCk7CisKK3N0cnVjdCBzZ190YWJsZSAq aTkxNV9zZ19mcm9tX2J1ZGR5X3Jlc291cmNlKHN0cnVjdCB0dG1fcmVzb3VyY2UgKnJlcywKKwkJ CQkJICAgICB1NjQgcmVnaW9uX3N0YXJ0KTsKKwogI2VuZGlmCi0tIAoyLjI2LjMKCl9fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCkludGVsLWdmeCBtYWlsaW5n IGxpc3QKSW50ZWwtZ2Z4QGxpc3RzLmZyZWVkZXNrdG9wLm9yZwpodHRwczovL2xpc3RzLmZyZWVk ZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2ludGVsLWdmeAo=