From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:45586 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752601AbdKMLxQ (ORCPT ); Mon, 13 Nov 2017 06:53:16 -0500 Date: Mon, 13 Nov 2017 11:53:14 +0000 From: Liviu Dudau To: Laurent Pinchart Cc: dri-devel@lists.freedesktop.org, linux-renesas-soc@vger.kernel.org, Kieran Bingham , Daniel Vetter Subject: Re: [PATCH/RFC 2/2] drm: rcar-du: Allow importing non-contiguous dma-buf with VSP Message-ID: <20171113115314.GB26389@e110455-lin.cambridge.arm.com> References: <20171113103228.23312-1-laurent.pinchart+renesas@ideasonboard.com> <20171113103228.23312-3-laurent.pinchart+renesas@ideasonboard.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20171113103228.23312-3-laurent.pinchart+renesas@ideasonboard.com> Sender: linux-renesas-soc-owner@vger.kernel.org List-ID: On Mon, Nov 13, 2017 at 12:32:28PM +0200, Laurent Pinchart wrote: > When the DU sources its frames from a VSP, it performs no memory access > and thus has no requirements on imported dma-buf memory types. In > particular the DU could import a physically non-contiguous buffer that > would later be mapped contiguously through the VSP IOMMU. > > This use case isn't supported at the moment as the GEM CMA helpers will > reject any non-contiguous buffer, and the DU isn't connected to an IOMMU > that can make the buffer contiguous for DMA. Fix this by implementing a > custom .gem_prime_import_sg_table() operation that accepts all imported > dma-buf regardless of the number of scatterlist entries. This patch raises the question of why use CMA at all if you can accept any kind of buffers. > > Signed-off-by: Laurent Pinchart > --- > drivers/gpu/drm/rcar-du/rcar_du_drv.c | 2 +- > drivers/gpu/drm/rcar-du/rcar_du_kms.c | 39 +++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/rcar-du/rcar_du_kms.h | 7 +++++++ > 3 files changed, 47 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c > index 48c166f925a3..d999231f98c7 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c > +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c > @@ -289,7 +289,7 @@ static struct drm_driver rcar_du_driver = { > .gem_prime_import = drm_gem_prime_import, > .gem_prime_export = drm_gem_prime_export, > .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, > - .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, > + .gem_prime_import_sg_table = rcar_du_gem_prime_import_sg_table, > .gem_prime_vmap = drm_gem_cma_prime_vmap, > .gem_prime_vunmap = drm_gem_cma_prime_vunmap, > .gem_prime_mmap = drm_gem_cma_prime_mmap, > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c > index 566d1a948c8f..2dd0c2ba047d 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c > +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c > @@ -20,6 +20,7 @@ > #include > #include > > +#include > #include > #include > > @@ -148,6 +149,44 @@ const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc) > * Frame buffer > */ > > +struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev, > + struct dma_buf_attachment *attach, > + struct sg_table *sgt) > +{ > + struct rcar_du_device *rcdu = dev->dev_private; > + struct drm_gem_cma_object *cma_obj; > + struct drm_gem_object *gem_obj; > + int ret; > + > + if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) > + return drm_gem_cma_prime_import_sg_table(dev, attach, sgt); > + > + /* Create a CMA GEM buffer. */ > + cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL); > + if (!cma_obj) > + return ERR_PTR(-ENOMEM); > + gem_obj = &cma_obj->base; > + > + ret = drm_gem_object_init(dev, gem_obj, attach->dmabuf->size); > + if (ret) > + goto error; > + > + ret = drm_gem_create_mmap_offset(gem_obj); > + if (ret) { > + drm_gem_object_release(gem_obj); > + goto error; > + } > + > + cma_obj->paddr = 0; This is going to break drm_gem_cma_describe() if you are using it plus the rcar_du_plane_setup_scanout() unless I'm missing something besides familiarity with the RCAR driver code :) This function looks very similar to what I tried to do for mali-dp to allow the import of contiguous DMA buffers that have more than 1 sgt entries. In the end I gave up as I kept finding issues and went for the drm_gem_cma_prime_import_sg_table() changes. Maybe you need to do a similar change in the function to bypass some requirements if the driver signals that it can accept relaxed requirements? Best regards, Liviu > + cma_obj->sgt = sgt; > + > + return gem_obj; > + > +error: > + kfree(cma_obj); > + return ERR_PTR(ret); > +} > + > int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, > struct drm_mode_create_dumb *args) > { > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h > index 07951d5fe38b..10b2bb0f0df9 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h > +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h > @@ -16,10 +16,13 @@ > > #include > > +struct dma_buf_attachment; > struct drm_file; > struct drm_device; > +struct drm_gem_object; > struct drm_mode_create_dumb; > struct rcar_du_device; > +struct sg_table; > > struct rcar_du_format_info { > u32 fourcc; > @@ -36,4 +39,8 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu); > int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, > struct drm_mode_create_dumb *args); > > +struct drm_gem_object *rcar_du_gem_prime_import_sg_table(struct drm_device *dev, > + struct dma_buf_attachment *attach, > + struct sg_table *sgt); > + > #endif /* __RCAR_DU_KMS_H__ */ > -- > Regards, > > Laurent Pinchart > -- ==================== | I would like to | | fix the world, | | but they're not | | giving me the | \ source code! / --------------- ¯\_(ツ)_/¯ From mboxrd@z Thu Jan 1 00:00:00 1970 From: Liviu Dudau Subject: Re: [PATCH/RFC 2/2] drm: rcar-du: Allow importing non-contiguous dma-buf with VSP Date: Mon, 13 Nov 2017 11:53:14 +0000 Message-ID: <20171113115314.GB26389@e110455-lin.cambridge.arm.com> References: <20171113103228.23312-1-laurent.pinchart+renesas@ideasonboard.com> <20171113103228.23312-3-laurent.pinchart+renesas@ideasonboard.com> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: Received: from foss.arm.com (usa-sjc-mx-foss1.foss.arm.com [217.140.101.70]) by gabe.freedesktop.org (Postfix) with ESMTP id E45A16E59A for ; Mon, 13 Nov 2017 11:53:16 +0000 (UTC) Content-Disposition: inline In-Reply-To: <20171113103228.23312-3-laurent.pinchart+renesas@ideasonboard.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Laurent Pinchart Cc: linux-renesas-soc@vger.kernel.org, Daniel Vetter , Kieran Bingham , dri-devel@lists.freedesktop.org List-Id: dri-devel@lists.freedesktop.org T24gTW9uLCBOb3YgMTMsIDIwMTcgYXQgMTI6MzI6MjhQTSArMDIwMCwgTGF1cmVudCBQaW5jaGFy dCB3cm90ZToKPiBXaGVuIHRoZSBEVSBzb3VyY2VzIGl0cyBmcmFtZXMgZnJvbSBhIFZTUCwgaXQg cGVyZm9ybXMgbm8gbWVtb3J5IGFjY2Vzcwo+IGFuZCB0aHVzIGhhcyBubyByZXF1aXJlbWVudHMg b24gaW1wb3J0ZWQgZG1hLWJ1ZiBtZW1vcnkgdHlwZXMuIEluCj4gcGFydGljdWxhciB0aGUgRFUg Y291bGQgaW1wb3J0IGEgcGh5c2ljYWxseSBub24tY29udGlndW91cyBidWZmZXIgdGhhdAo+IHdv dWxkIGxhdGVyIGJlIG1hcHBlZCBjb250aWd1b3VzbHkgdGhyb3VnaCB0aGUgVlNQIElPTU1VLgo+ IAo+IFRoaXMgdXNlIGNhc2UgaXNuJ3Qgc3VwcG9ydGVkIGF0IHRoZSBtb21lbnQgYXMgdGhlIEdF TSBDTUEgaGVscGVycyB3aWxsCj4gcmVqZWN0IGFueSBub24tY29udGlndW91cyBidWZmZXIsIGFu ZCB0aGUgRFUgaXNuJ3QgY29ubmVjdGVkIHRvIGFuIElPTU1VCj4gdGhhdCBjYW4gbWFrZSB0aGUg YnVmZmVyIGNvbnRpZ3VvdXMgZm9yIERNQS4gRml4IHRoaXMgYnkgaW1wbGVtZW50aW5nIGEKPiBj dXN0b20gLmdlbV9wcmltZV9pbXBvcnRfc2dfdGFibGUoKSBvcGVyYXRpb24gdGhhdCBhY2NlcHRz IGFsbCBpbXBvcnRlZAo+IGRtYS1idWYgcmVnYXJkbGVzcyBvZiB0aGUgbnVtYmVyIG9mIHNjYXR0 ZXJsaXN0IGVudHJpZXMuCgpUaGlzIHBhdGNoIHJhaXNlcyB0aGUgcXVlc3Rpb24gb2Ygd2h5IHVz ZSBDTUEgYXQgYWxsIGlmIHlvdSBjYW4gYWNjZXB0CmFueSBraW5kIG9mIGJ1ZmZlcnMuCgo+IAo+ IFNpZ25lZC1vZmYtYnk6IExhdXJlbnQgUGluY2hhcnQgPGxhdXJlbnQucGluY2hhcnQrcmVuZXNh c0BpZGVhc29uYm9hcmQuY29tPgo+IC0tLQo+ICBkcml2ZXJzL2dwdS9kcm0vcmNhci1kdS9yY2Fy X2R1X2Rydi5jIHwgIDIgKy0KPiAgZHJpdmVycy9ncHUvZHJtL3JjYXItZHUvcmNhcl9kdV9rbXMu YyB8IDM5ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrCj4gIGRyaXZlcnMvZ3B1 L2RybS9yY2FyLWR1L3JjYXJfZHVfa21zLmggfCAgNyArKysrKysrCj4gIDMgZmlsZXMgY2hhbmdl ZCwgNDcgaW5zZXJ0aW9ucygrKSwgMSBkZWxldGlvbigtKQo+IAo+IGRpZmYgLS1naXQgYS9kcml2 ZXJzL2dwdS9kcm0vcmNhci1kdS9yY2FyX2R1X2Rydi5jIGIvZHJpdmVycy9ncHUvZHJtL3JjYXIt ZHUvcmNhcl9kdV9kcnYuYwo+IGluZGV4IDQ4YzE2NmY5MjVhMy4uZDk5OTIzMWY5OGM3IDEwMDY0 NAo+IC0tLSBhL2RyaXZlcnMvZ3B1L2RybS9yY2FyLWR1L3JjYXJfZHVfZHJ2LmMKPiArKysgYi9k cml2ZXJzL2dwdS9kcm0vcmNhci1kdS9yY2FyX2R1X2Rydi5jCj4gQEAgLTI4OSw3ICsyODksNyBA QCBzdGF0aWMgc3RydWN0IGRybV9kcml2ZXIgcmNhcl9kdV9kcml2ZXIgPSB7Cj4gIAkuZ2VtX3By aW1lX2ltcG9ydAk9IGRybV9nZW1fcHJpbWVfaW1wb3J0LAo+ICAJLmdlbV9wcmltZV9leHBvcnQJ PSBkcm1fZ2VtX3ByaW1lX2V4cG9ydCwKPiAgCS5nZW1fcHJpbWVfZ2V0X3NnX3RhYmxlCT0gZHJt X2dlbV9jbWFfcHJpbWVfZ2V0X3NnX3RhYmxlLAo+IC0JLmdlbV9wcmltZV9pbXBvcnRfc2dfdGFi bGUgPSBkcm1fZ2VtX2NtYV9wcmltZV9pbXBvcnRfc2dfdGFibGUsCj4gKwkuZ2VtX3ByaW1lX2lt cG9ydF9zZ190YWJsZSA9IHJjYXJfZHVfZ2VtX3ByaW1lX2ltcG9ydF9zZ190YWJsZSwKPiAgCS5n ZW1fcHJpbWVfdm1hcAkJPSBkcm1fZ2VtX2NtYV9wcmltZV92bWFwLAo+ICAJLmdlbV9wcmltZV92 dW5tYXAJPSBkcm1fZ2VtX2NtYV9wcmltZV92dW5tYXAsCj4gIAkuZ2VtX3ByaW1lX21tYXAJCT0g ZHJtX2dlbV9jbWFfcHJpbWVfbW1hcCwKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9ncHUvZHJtL3Jj YXItZHUvcmNhcl9kdV9rbXMuYyBiL2RyaXZlcnMvZ3B1L2RybS9yY2FyLWR1L3JjYXJfZHVfa21z LmMKPiBpbmRleCA1NjZkMWE5NDhjOGYuLjJkZDBjMmJhMDQ3ZCAxMDA2NDQKPiAtLS0gYS9kcml2 ZXJzL2dwdS9kcm0vcmNhci1kdS9yY2FyX2R1X2ttcy5jCj4gKysrIGIvZHJpdmVycy9ncHUvZHJt L3JjYXItZHUvcmNhcl9kdV9rbXMuYwo+IEBAIC0yMCw2ICsyMCw3IEBACj4gICNpbmNsdWRlIDxk cm0vZHJtX2dlbV9jbWFfaGVscGVyLmg+Cj4gICNpbmNsdWRlIDxkcm0vZHJtX2dlbV9mcmFtZWJ1 ZmZlcl9oZWxwZXIuaD4KPiAgCj4gKyNpbmNsdWRlIDxsaW51eC9kbWEtYnVmLmg+Cj4gICNpbmNs dWRlIDxsaW51eC9vZl9ncmFwaC5oPgo+ICAjaW5jbHVkZSA8bGludXgvd2FpdC5oPgo+ICAKPiBA QCAtMTQ4LDYgKzE0OSw0NCBAQCBjb25zdCBzdHJ1Y3QgcmNhcl9kdV9mb3JtYXRfaW5mbyAqcmNh cl9kdV9mb3JtYXRfaW5mbyh1MzIgZm91cmNjKQo+ICAgKiBGcmFtZSBidWZmZXIKPiAgICovCj4g IAo+ICtzdHJ1Y3QgZHJtX2dlbV9vYmplY3QgKnJjYXJfZHVfZ2VtX3ByaW1lX2ltcG9ydF9zZ190 YWJsZShzdHJ1Y3QgZHJtX2RldmljZSAqZGV2LAo+ICsJCQkJc3RydWN0IGRtYV9idWZfYXR0YWNo bWVudCAqYXR0YWNoLAo+ICsJCQkJc3RydWN0IHNnX3RhYmxlICpzZ3QpCj4gK3sKPiArCXN0cnVj dCByY2FyX2R1X2RldmljZSAqcmNkdSA9IGRldi0+ZGV2X3ByaXZhdGU7Cj4gKwlzdHJ1Y3QgZHJt X2dlbV9jbWFfb2JqZWN0ICpjbWFfb2JqOwo+ICsJc3RydWN0IGRybV9nZW1fb2JqZWN0ICpnZW1f b2JqOwo+ICsJaW50IHJldDsKPiArCj4gKwlpZiAoIXJjYXJfZHVfaGFzKHJjZHUsIFJDQVJfRFVf RkVBVFVSRV9WU1AxX1NPVVJDRSkpCj4gKwkJcmV0dXJuIGRybV9nZW1fY21hX3ByaW1lX2ltcG9y dF9zZ190YWJsZShkZXYsIGF0dGFjaCwgc2d0KTsKPiArCj4gKwkvKiBDcmVhdGUgYSBDTUEgR0VN IGJ1ZmZlci4gKi8KPiArCWNtYV9vYmogPSBremFsbG9jKHNpemVvZigqY21hX29iaiksIEdGUF9L RVJORUwpOwo+ICsJaWYgKCFjbWFfb2JqKQo+ICsJCXJldHVybiBFUlJfUFRSKC1FTk9NRU0pOwo+ ICsJZ2VtX29iaiA9ICZjbWFfb2JqLT5iYXNlOwo+ICsKPiArCXJldCA9IGRybV9nZW1fb2JqZWN0 X2luaXQoZGV2LCBnZW1fb2JqLCBhdHRhY2gtPmRtYWJ1Zi0+c2l6ZSk7Cj4gKwlpZiAocmV0KQo+ ICsJCWdvdG8gZXJyb3I7Cj4gKwo+ICsJcmV0ID0gZHJtX2dlbV9jcmVhdGVfbW1hcF9vZmZzZXQo Z2VtX29iaik7Cj4gKwlpZiAocmV0KSB7Cj4gKwkJZHJtX2dlbV9vYmplY3RfcmVsZWFzZShnZW1f b2JqKTsKPiArCQlnb3RvIGVycm9yOwo+ICsJfQo+ICsKPiArCWNtYV9vYmotPnBhZGRyID0gMDsK ClRoaXMgaXMgZ29pbmcgdG8gYnJlYWsgZHJtX2dlbV9jbWFfZGVzY3JpYmUoKSBpZiB5b3UgYXJl IHVzaW5nIGl0IHBsdXMKdGhlIHJjYXJfZHVfcGxhbmVfc2V0dXBfc2Nhbm91dCgpIHVubGVzcyBJ J20gbWlzc2luZyBzb21ldGhpbmcgYmVzaWRlcwpmYW1pbGlhcml0eSB3aXRoIHRoZSBSQ0FSIGRy aXZlciBjb2RlIDopCgpUaGlzIGZ1bmN0aW9uIGxvb2tzIHZlcnkgc2ltaWxhciB0byB3aGF0IEkg dHJpZWQgdG8gZG8gZm9yIG1hbGktZHAgdG8KYWxsb3cgdGhlIGltcG9ydCBvZiBjb250aWd1b3Vz IERNQSBidWZmZXJzIHRoYXQgaGF2ZSBtb3JlIHRoYW4gMSBzZ3QKZW50cmllcy4gSW4gdGhlIGVu ZCBJIGdhdmUgdXAgYXMgSSBrZXB0IGZpbmRpbmcgaXNzdWVzIGFuZCB3ZW50IGZvciB0aGUKZHJt X2dlbV9jbWFfcHJpbWVfaW1wb3J0X3NnX3RhYmxlKCkgY2hhbmdlcy4gTWF5YmUgeW91IG5lZWQg dG8gZG8gYQpzaW1pbGFyIGNoYW5nZSBpbiB0aGUgZnVuY3Rpb24gdG8gYnlwYXNzIHNvbWUgcmVx dWlyZW1lbnRzIGlmIHRoZSBkcml2ZXIKc2lnbmFscyB0aGF0IGl0IGNhbiBhY2NlcHQgcmVsYXhl ZCByZXF1aXJlbWVudHM/CgpCZXN0IHJlZ2FyZHMsCkxpdml1Cgo+ICsJY21hX29iai0+c2d0ID0g c2d0Owo+ICsKPiArCXJldHVybiBnZW1fb2JqOwo+ICsKPiArZXJyb3I6Cj4gKwlrZnJlZShjbWFf b2JqKTsKPiArCXJldHVybiBFUlJfUFRSKHJldCk7Cj4gK30KPiArCj4gIGludCByY2FyX2R1X2R1 bWJfY3JlYXRlKHN0cnVjdCBkcm1fZmlsZSAqZmlsZSwgc3RydWN0IGRybV9kZXZpY2UgKmRldiwK PiAgCQkJc3RydWN0IGRybV9tb2RlX2NyZWF0ZV9kdW1iICphcmdzKQo+ICB7Cj4gZGlmZiAtLWdp dCBhL2RyaXZlcnMvZ3B1L2RybS9yY2FyLWR1L3JjYXJfZHVfa21zLmggYi9kcml2ZXJzL2dwdS9k cm0vcmNhci1kdS9yY2FyX2R1X2ttcy5oCj4gaW5kZXggMDc5NTFkNWZlMzhiLi4xMGIyYmIwZjBk ZjkgMTAwNjQ0Cj4gLS0tIGEvZHJpdmVycy9ncHUvZHJtL3JjYXItZHUvcmNhcl9kdV9rbXMuaAo+ ICsrKyBiL2RyaXZlcnMvZ3B1L2RybS9yY2FyLWR1L3JjYXJfZHVfa21zLmgKPiBAQCAtMTYsMTAg KzE2LDEzIEBACj4gIAo+ICAjaW5jbHVkZSA8bGludXgvdHlwZXMuaD4KPiAgCj4gK3N0cnVjdCBk bWFfYnVmX2F0dGFjaG1lbnQ7Cj4gIHN0cnVjdCBkcm1fZmlsZTsKPiAgc3RydWN0IGRybV9kZXZp Y2U7Cj4gK3N0cnVjdCBkcm1fZ2VtX29iamVjdDsKPiAgc3RydWN0IGRybV9tb2RlX2NyZWF0ZV9k dW1iOwo+ICBzdHJ1Y3QgcmNhcl9kdV9kZXZpY2U7Cj4gK3N0cnVjdCBzZ190YWJsZTsKPiAgCj4g IHN0cnVjdCByY2FyX2R1X2Zvcm1hdF9pbmZvIHsKPiAgCXUzMiBmb3VyY2M7Cj4gQEAgLTM2LDQg KzM5LDggQEAgaW50IHJjYXJfZHVfbW9kZXNldF9pbml0KHN0cnVjdCByY2FyX2R1X2RldmljZSAq cmNkdSk7Cj4gIGludCByY2FyX2R1X2R1bWJfY3JlYXRlKHN0cnVjdCBkcm1fZmlsZSAqZmlsZSwg c3RydWN0IGRybV9kZXZpY2UgKmRldiwKPiAgCQkJc3RydWN0IGRybV9tb2RlX2NyZWF0ZV9kdW1i ICphcmdzKTsKPiAgCj4gK3N0cnVjdCBkcm1fZ2VtX29iamVjdCAqcmNhcl9kdV9nZW1fcHJpbWVf aW1wb3J0X3NnX3RhYmxlKHN0cnVjdCBkcm1fZGV2aWNlICpkZXYsCj4gKwkJCQlzdHJ1Y3QgZG1h X2J1Zl9hdHRhY2htZW50ICphdHRhY2gsCj4gKwkJCQlzdHJ1Y3Qgc2dfdGFibGUgKnNndCk7Cj4g Kwo+ICAjZW5kaWYgLyogX19SQ0FSX0RVX0tNU19IX18gKi8KPiAtLSAKPiBSZWdhcmRzLAo+IAo+ IExhdXJlbnQgUGluY2hhcnQKPiAKCi0tIAo9PT09PT09PT09PT09PT09PT09PQp8IEkgd291bGQg bGlrZSB0byB8CnwgZml4IHRoZSB3b3JsZCwgIHwKfCBidXQgdGhleSdyZSBub3QgfAp8IGdpdmlu ZyBtZSB0aGUgICB8CiBcIHNvdXJjZSBjb2RlISAgLwogIC0tLS0tLS0tLS0tLS0tLQogICAgwq9c Xyjjg4QpXy/CrwpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f XwpkcmktZGV2ZWwgbWFpbGluZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcK aHR0cHM6Ly9saXN0cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9kcmktZGV2ZWwK