From mboxrd@z Thu Jan 1 00:00:00 1970 From: Matthew Dawson Subject: Re: [PATCH] drm/radeon: Avoid double gpu reset by adding a timeout on IB ring tests. Date: Sun, 31 Jan 2016 13:50:38 -0500 Message-ID: <1689212.YJ1RXmWsVz@ring00> References: <1453616332-30763-1-git-send-email-matthew@mjdsystems.ca> <56A49E0C.1060105@vodafone.de> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1596145627==" Return-path: Received: from scadrial.mjdsystems.ca (scadrial.mjdsystems.ca [198.100.154.185]) by gabe.freedesktop.org (Postfix) with ESMTP id 5CD906E1E5 for ; Sun, 31 Jan 2016 10:50:44 -0800 (PST) In-Reply-To: <56A49E0C.1060105@vodafone.de> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Christian =?ISO-8859-1?Q?K=F6nig?= Cc: dri-devel@lists.freedesktop.org List-Id: dri-devel@lists.freedesktop.org --===============1596145627== Content-Type: multipart/signed; boundary="nextPart46915898.zDM0d8cqMm"; micalg="sha256"; protocol="application/pkcs7-signature" --nextPart46915898.zDM0d8cqMm Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="iso-8859-1" On Sunday, January 24, 2016 10:49:00 AM EST Christian K=F6nig wrote: > Am 24.01.2016 um 07:18 schrieb Matthew Dawson: > > When the radeon driver resets a gpu, it attempts to test whether all the > > rings can successfully handle an IB. If these rings fail to respond, t= he > > process will wait forever. Another gpu reset can't happen at this poin= t, > > as the current reset holds a lock required to do so. Instead, make all > > the IB tests run with a timeout, so the system can attempt to recover > > in this case. > >=20 > > While this doesn't fix the underlying issue with card resets failing, it > > gives the system a higher chance of recovering. These timeouts have be= en > > confirmed to help both a Tathi and Hawaii card recover after a gpu rese= t. > >=20 > > I haven't been able to test this on other cards, but everything compile= s. > > I wasn't sure what to use for a timeout value, so for now I've used > > radeon_lockup_timeout. When that is 0, the timeout functionality in th= is > > patch is also disabled. > >=20 > > This also adds a new function, radeon_fence_wait_timeout, that behaves > > like > > radeon_fence_wait except allowing a different timeout value to be passed > > to > > radeon_fence_wait_seq_timeout. > >=20 > > Signed-off-by: Matthew Dawson >=20 > Really good idea, but please don't use radeon_lockup_timeout for this > cause the 10 seconds default of that is way to long. Instead just use a > fixed, let's say 100ms timeout defined in radeon.h. I originally tried 100ms, but I found that to be too short (my system would= =20 just lockup completely (no network even)). I found 1s is long enough, and= =20 isn't so long to be annoying. Would that be ok? >=20 > Also don't define our own radeon_fence_wait_timeout, just use > fence_wait_timeout(&fence->base, RADEON_IB_TEST_TIMEOUT) for this. I switched everything over to this, however the ib test always times out af= ter=20 a gpu reset (on startup, everything is normal). I'm not sure why=20 fence_wait_timeout isn't being signaled while radeon_fence_wait_seq_timeout= =20 is. I'm suspicious that either radeon_fence_enable_signaling is not doing= =20 something necessary to get the fence completion to actual signal=20 radeon_fence_default_wait, or because we hold the exclusive lock during a=20 reset radeon_fence_check_lockup never runs and thus never triggers the fenc= e=20 or enables some irq lines. Is it worth digging through the interactions here to get dma-buf fences to= =20 work correctly during a lockup, or would it be better to just keep=20 radeon_fence_wait_timeout? If option 1 is preferred, I'm happy to learn bu= t I=20 need some help learning how it is supposed to work. >=20 > Apart from that the idea looks really good to me. >=20 > Regards, > Christian. >=20 Thanks, Matthew > > --- > >=20 > > drivers/gpu/drm/radeon/cik_sdma.c | 3 ++- > > drivers/gpu/drm/radeon/r100.c | 3 ++- > > drivers/gpu/drm/radeon/r600.c | 3 ++- > > drivers/gpu/drm/radeon/r600_dma.c | 3 ++- > > drivers/gpu/drm/radeon/radeon.h | 1 + > > drivers/gpu/drm/radeon/radeon_fence.c | 25 ++++++++++++++++++++++--- > > drivers/gpu/drm/radeon/radeon_vce.c | 3 ++- > > drivers/gpu/drm/radeon/uvd_v1_0.c | 3 ++- > > 8 files changed, 35 insertions(+), 9 deletions(-) > >=20 > > diff --git a/drivers/gpu/drm/radeon/cik_sdma.c > > b/drivers/gpu/drm/radeon/cik_sdma.c index d16f2ee..014f5ca 100644 > > --- a/drivers/gpu/drm/radeon/cik_sdma.c > > +++ b/drivers/gpu/drm/radeon/cik_sdma.c > > @@ -737,7 +737,8 @@ int cik_sdma_ib_test(struct radeon_device *rdev, > > struct radeon_ring *ring)>=20 > > DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); > > return r; > > =09 > > } > >=20 > > - r =3D radeon_fence_wait(ib.fence, false); > > + r =3D radeon_fence_wait_timeout(ib.fence, false, msecs_to_jiffies( > > + (radeon_lockup_timeout) ? radeon_lockup_timeout : > > MAX_SCHEDULE_TIMEOUT));>=20 > > if (r) { > > =09 > > DRM_ERROR("radeon: fence wait failed (%d).\n", r); > > return r; > >=20 > > diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r10= 0.c > > index 5eae0a8..5386c09 100644 > > --- a/drivers/gpu/drm/radeon/r100.c > > +++ b/drivers/gpu/drm/radeon/r100.c > > @@ -3732,7 +3732,8 @@ int r100_ib_test(struct radeon_device *rdev, stru= ct > > radeon_ring *ring)>=20 > > DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); > > goto free_ib; > > =09 > > } > >=20 > > - r =3D radeon_fence_wait(ib.fence, false); > > + r =3D radeon_fence_wait_timeout(ib.fence, false, msecs_to_jiffies( > > + (radeon_lockup_timeout) ? radeon_lockup_timeout : > > MAX_SCHEDULE_TIMEOUT));>=20 > > if (r) { > > =09 > > DRM_ERROR("radeon: fence wait failed (%d).\n", r); > > goto free_ib; > >=20 > > diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r60= 0.c > > index cc2fdf0..8fbe5d7 100644 > > --- a/drivers/gpu/drm/radeon/r600.c > > +++ b/drivers/gpu/drm/radeon/r600.c > > @@ -3381,7 +3381,8 @@ int r600_ib_test(struct radeon_device *rdev, stru= ct > > radeon_ring *ring)>=20 > > DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); > > goto free_ib; > > =09 > > } > >=20 > > - r =3D radeon_fence_wait(ib.fence, false); > > + r =3D radeon_fence_wait_timeout(ib.fence, false, msecs_to_jiffies( > > + (radeon_lockup_timeout) ? radeon_lockup_timeout : > > MAX_SCHEDULE_TIMEOUT));>=20 > > if (r) { > > =09 > > DRM_ERROR("radeon: fence wait failed (%d).\n", r); > > goto free_ib; > >=20 > > diff --git a/drivers/gpu/drm/radeon/r600_dma.c > > b/drivers/gpu/drm/radeon/r600_dma.c index d2dd29a..3ff614d 100644 > > --- a/drivers/gpu/drm/radeon/r600_dma.c > > +++ b/drivers/gpu/drm/radeon/r600_dma.c > > @@ -368,7 +368,8 @@ int r600_dma_ib_test(struct radeon_device *rdev, > > struct radeon_ring *ring)>=20 > > DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); > > return r; > > =09 > > } > >=20 > > - r =3D radeon_fence_wait(ib.fence, false); > > + r =3D radeon_fence_wait_timeout(ib.fence, false, msecs_to_jiffies( > > + (radeon_lockup_timeout) ? radeon_lockup_timeout : > > MAX_SCHEDULE_TIMEOUT));>=20 > > if (r) { > > =09 > > DRM_ERROR("radeon: fence wait failed (%d).\n", r); > > return r; > >=20 > > diff --git a/drivers/gpu/drm/radeon/radeon.h > > b/drivers/gpu/drm/radeon/radeon.h index 5ae6db9..0b698b6 100644 > > --- a/drivers/gpu/drm/radeon/radeon.h > > +++ b/drivers/gpu/drm/radeon/radeon.h > > @@ -382,6 +382,7 @@ void radeon_fence_driver_force_completion(struct > > radeon_device *rdev, int ring);>=20 > > int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence > > **fence, int ring); void radeon_fence_process(struct radeon_device > > *rdev, int ring); > > bool radeon_fence_signaled(struct radeon_fence *fence); > >=20 > > +int radeon_fence_wait_timeout(struct radeon_fence *fence, bool > > interruptible, long timeout);>=20 > > int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); > > int radeon_fence_wait_next(struct radeon_device *rdev, int ring); > > int radeon_fence_wait_empty(struct radeon_device *rdev, int ring); > >=20 > > diff --git a/drivers/gpu/drm/radeon/radeon_fence.c > > b/drivers/gpu/drm/radeon/radeon_fence.c index 05815c4..9fec805 100644 > > --- a/drivers/gpu/drm/radeon/radeon_fence.c > > +++ b/drivers/gpu/drm/radeon/radeon_fence.c > > @@ -527,7 +527,7 @@ static long radeon_fence_wait_seq_timeout(struct > > radeon_device *rdev,>=20 > > } > > =20 > > /** > >=20 > > - * radeon_fence_wait - wait for a fence to signal > > + * radeon_fence_wait_timeout - wait for a fence to signal with timeout > >=20 > > * > > * @fence: radeon fence object > > * @intr: use interruptible sleep > >=20 > > @@ -535,9 +535,10 @@ static long radeon_fence_wait_seq_timeout(struct > > radeon_device *rdev,>=20 > > * Wait for the requested fence to signal (all asics). > > * @intr selects whether to use interruptable (true) or > > non-interruptable > > * (false) sleep when waiting for the fence. > >=20 > > + * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite > > wait>=20 > > * Returns 0 if the fence has passed, error for all other cases. > > */ > >=20 > > -int radeon_fence_wait(struct radeon_fence *fence, bool intr) > > +int radeon_fence_wait_timeout(struct radeon_fence *fence, bool intr, l= ong > > timeout)>=20 > > { > > =20 > > uint64_t seq[RADEON_NUM_RINGS] =3D {}; > > long r; > >=20 > > @@ -552,9 +553,11 @@ int radeon_fence_wait(struct radeon_fence *fence, > > bool intr)>=20 > > return fence_wait(&fence->base, intr); > > =09 > > seq[fence->ring] =3D fence->seq; > >=20 > > - r =3D radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, > > MAX_SCHEDULE_TIMEOUT); + r =3D radeon_fence_wait_seq_timeout(fence->rde= v, > > seq, intr, timeout);>=20 > > if (r < 0) { > > =09 > > return r; > >=20 > > + } else if (r =3D=3D 0) { > > + return -ETIMEDOUT; > >=20 > > } > > =09 > > r =3D fence_signal(&fence->base); > >=20 > > @@ -564,6 +567,22 @@ int radeon_fence_wait(struct radeon_fence *fence, > > bool intr)>=20 > > } > > =20 > > /** > >=20 > > + * radeon_fence_wait - wait for a fence to signal > > + * > > + * @fence: radeon fence object > > + * @intr: use interruptible sleep > > + * > > + * Wait for the requested fence to signal (all asics). > > + * @intr selects whether to use interruptable (true) or non-interrupta= ble > > + * (false) sleep when waiting for the fence. > > + * Returns 0 if the fence has passed, error for all other cases. > > + */ > > +int radeon_fence_wait(struct radeon_fence *fence, bool intr) > > +{ > > + return radeon_fence_wait_timeout(fence, intr, MAX_SCHEDULE_TIMEOUT); > > +} > > + > > +/** > >=20 > > * radeon_fence_wait_any - wait for a fence to signal on any ring > > * > > * @rdev: radeon device pointer > >=20 > > diff --git a/drivers/gpu/drm/radeon/radeon_vce.c > > b/drivers/gpu/drm/radeon/radeon_vce.c index 7eb1ae7..7d80dad 100644 > > --- a/drivers/gpu/drm/radeon/radeon_vce.c > > +++ b/drivers/gpu/drm/radeon/radeon_vce.c > > @@ -810,7 +810,8 @@ int radeon_vce_ib_test(struct radeon_device *rdev, > > struct radeon_ring *ring)>=20 > > goto error; > > =09 > > } > >=20 > > - r =3D radeon_fence_wait(fence, false); > > + r =3D radeon_fence_wait_timeout(fence, false, msecs_to_jiffies( > > + (radeon_lockup_timeout) ? radeon_lockup_timeout : > > MAX_SCHEDULE_TIMEOUT));>=20 > > if (r) { > > =09 > > DRM_ERROR("radeon: fence wait failed (%d).\n", r); > > =09 > > } else { > >=20 > > diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c > > b/drivers/gpu/drm/radeon/uvd_v1_0.c index c6b1cbc..35caa89 100644 > > --- a/drivers/gpu/drm/radeon/uvd_v1_0.c > > +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c > > @@ -522,7 +522,8 @@ int uvd_v1_0_ib_test(struct radeon_device *rdev, > > struct radeon_ring *ring)>=20 > > goto error; > > =09 > > } > >=20 > > - r =3D radeon_fence_wait(fence, false); > > + r =3D radeon_fence_wait_timeout(fence, false, msecs_to_jiffies( > > + (radeon_lockup_timeout) ? radeon_lockup_timeout : > > MAX_SCHEDULE_TIMEOUT));>=20 > > if (r) { > > =09 > > DRM_ERROR("radeon: fence wait failed (%d).\n", r); > > goto error; =2D-=20 Matthew --nextPart46915898.zDM0d8cqMm Content-Type: application/pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCEzkw ggafMIIEh6ADAgECAgE9MA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1T dGFydENvbSBMdGQuMSwwKgYDVQQDEyNTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBH MjAeFw0wNjA5MTcxOTQ2MzdaFw0zNjA5MTcxOTQ2MzdaMH0xCzAJBgNVBAYTAklMMRYwFAYDVQQK Ew1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWdu aW5nMSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZI hvcNAQEBBQADggIPADCCAgoCggIBAMGI2wm8bEZ8eJ+Ve7UzkPJyYtbBNiAiJF7O6XfyQwqiBmSk zI42+DjmI/BubbE83XKjhRyh0z20MyvTL6/+6rBBWWe2xAZ9Cp50hdZ5TIA3et85BVJZ9/QbRkOk 0oWF0sNx83ViNLosin8ej+7tNNARx5bNUj26M9bdTd4LO0pLn8ImL/q1FhxyNXfKPF3myuEmixo2 dlwB23QUJf7ttaCID914yi0fB5cwAS1yefpG1hMqqLmmq4NJHeXy793kAY4YCo9jUxaFYqkOGTrM tWamwmt0B+Qr4XY+tG3Y9kThc2IfO8S+oFNWJWxRCfeqq8q/dv1tm/Od2789ZrwMVqqvmEiVOkvf p1hQ2Th1qVvqQwwC/5nr6GxNcFspZZzdql3MrwEx7Azr0o3o6px75m73J2YMGkjXbkLjP94hPnvh DXD7Y6qobBpUtFwlesmiyYsWprssfhdeBU1YbhIdAe4SEA3GMn8Y//z0+s1ukeg2Sb4aSGmLwpZN GhKyaRfBCpDW+nkiSL+6e2n4cMf6ejfY2A3Sdk9X/5C345HS3e/CYLdnOt3+qpzw1It/ciLOxp+X tviviqAQqNn7GMa2tVxSPIm2GSpzAQoPA7MSYPJ6L4Hbo27/JjCX9YvdiVe2rT2zryvFt3YC8KXW K5qGFCpy9uMzjF0JSxPfu4x0E1JLAgMBAAGjggFSMIIBTjASBgNVHRMBAf8ECDAGAQH/AgECMA4G A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwHwYDVR0jBBgwFoAU S8W0QGutHLOlHGVuRjaJhwUMDrYwbwYIKwYBBQUHAQEEYzBhMCoGCCsGAQUFBzABhh5odHRwOi8v b2NzcC5zdGFydHNzbC5jb20vY2EtZzIwMwYIKwYBBQUHMAKGJ2h0dHA6Ly9haWEuc3RhcnRzc2wu Y29tL2NlcnRzL2NhLWcyLmNlcjAyBgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3Ns LmNvbS9jYS1nMi5jcmwwQwYDVR0gBDwwOjA4BgRVHSAAMDAwLgYIKwYBBQUHAgEWImh0dHA6Ly93 d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwDQYJKoZIhvcNAQELBQADggIBADOeU8uuVCwCibCV VgaCtEd5cJdIDwrQTTdrVV8ITy6GBFmDtwrc3agSiMEyh4vhWos566px3fP7FKrzm7GfM9z5wAFu JFviC7JC8r92rNaOOYNwRhWTSjMKpaIGT55zhbgeaDKRAd2+Fj7zOAlIJB1+oaSEBRzX9T+ITmMA i9zczvucV4nooh7dVqcQEOy0XOVCElKjylLOEvykRgFam50dqdsWiBkMnAb4YLqkTw9KcgQAeYsp fChF5KvrGgelQOsx3AKG2HTSBFgLPjkA6uRPKUisiXwSXPNdu2MGsIUwohy2ZzFcTSxVzZhP04IJ Qv6bv8so811eikZt7wNYvoeYVTAYvB23y3lbNdVLFLfEADsXoMzPTnA1Prwl91/wGUnJDcdGJO/9 PbQFs1KpJWw5aykjK5o+EtHX9K/abg96sHmUlgDr9T94VnWi3yB7ndc4ig98P30sb1J53icXzbaj 90dJcBnxf6ii2gFfm2ID72F8ap9X8m6xhy/6FztKpF3NhNtyzqyL4SFGzWEpYuK582hAwc/6Vyik 5SW3cin+npYNk0k4mrjouC8MWPtxD9ZKQy7MDl+no0++NCdWaiONROxp2lE3iFudqOs7uuMmE4kE 3eRx3jXNrtlD2WHjb3LzLlNslZgngRuUfiuJBUoRCDKDiaqYI6WXIxhLsIYZMIIGNDCCBBygAwIB AgIBIDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjEwMjU1WhcNMTcxMDI0 MjEwMjU1WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENs YXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgQ2xpZW50IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAyyiFRZwBLPsZ8qulM4wqoA3L0FXtXSKBZ0bEDwhTvsvdpPEStD59zG0Nhnfp noYfRgWft+rlEAO14/QBjOsID4RBN+LyrX6QDebSfC3Bcb3gzmwiqy+zuVE/VrJwGR7+zmD2Ekev JnZpxJyfNzOMEICjtfW/kbfLDwwM/abZELJ7Qp+Bnic4N6tklXOECU4P1h6O8BdmoeSzDnofMSVU ihhJnerj5Em49dd8ijJvL5jabUT5jNfmIJlcHHTmCTowoBbW9rDj+/Y44vLoVkfdcce06TNSt4b/ 8KwWcH365phKVHrlx0bNOyaggrxYfXKCheFEGb3xIPsd/+vcUQs29QIDAQABo4IBrTCCAakwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFK5Vg2/sMcq59x36r2sx88gd 46y7MB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggr BgEFBQcwAYYbaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8v d3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3dy5z dGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNj YS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAuBggrBgEFBQcCARYiaHR0cDovL3d3 dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNz bC5jb20vaW50ZXJtZWRpYXRlLnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAOqknDcjTtBaR72mU0GnF TFx99zudSshCkkcNyL3UMUbt9WEdGQxnUn4EqDlQ1TEgUnZn0H3QyJxz81dyzuQ8FF2fpcY7+89z ztjpH5xZL01z35+ncSeayb3g7E7Aj3Cfyqev/qjeYPieg/0mmHBQ9NfAei+Nq9GeFRAct+j+LY0b RdeBMddLZebSRVSjNeqlikB26YyIH+97OPVAdAkOZR09gxyn6t6D33TXOTJPd8Nb+K8lW/qla2SH o/DbK1lPua+DtiFfdXnQ2/zrRxXXWahxRVyoEu/SBxP4cENi1u697E1+3A1AoPnX3cDvM3i8bsJN iRfHK1KMq5eukRq0SIU/FaBvzidWPblJTmr+vVeHBvLqYuGRtpeyWRW3ARZPdVqfj2sqOUrhetQp hha2d/OrppJqTm7RWnF3Wtjv21aEPcR0K86E3P9CmU1r5WQiytynv7xmE/WXVvZToxrEhW165UwP dfS/OIjCvuPFhp70VmNvGWlR6apeNwLRBoV83uojQmxAwAsvuIZEGDsrQKg4HMQJ0Pd+5mKXmRT8 s/1yvUErfVTRTLrnVsWcAwwySqEAKEhufR6LvZWdulKyutJ0XQEAZhDy/Idp7loKD4fvl1UJXfcr oW7Fmt/T3JPP5XH8+R1FRiReZnP85N/IlexQ5RevKboq8jatilxxKTkwggZaMIIFQqADAgECAgJJ PjANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4x KzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0 YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgQ2xpZW50IENBMB4XDTE0MDQwODE5 MzIxMloXDTE2MDQwOTAyNTIzMFowdDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xFDAS BgNVBAcTC01pc3Npc3NhdWdhMRcwFQYDVQQDEw5NYXR0aGV3IERhd3NvbjEkMCIGCSqGSIb3DQEJ ARYVbWF0dGhld0BtamRzeXN0ZW1zLmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA rEwVnAlwRQ6jtLTU199K5s9RQm9PI4Xem2rJ4bclgXQN3nC6BNJeSYAV/X1/HODe6OwCitfVUo1e 5IoHk+g09hBs7G84o5KWq3hauiXWWcz7riRD/a/rkO2H1DCkLG+uEmyTLt3sEKTGMrjwCpCxYHip l5IXDusm1cnOY9HmJre1NifOWtEQNcyW7XRICaEdxT0yzOGos3vVfFfbAcbu1LQJvXlHeuBkc5+O Q5Ryg1HU4eVmmKzBBpnNBSq5lKeIIblXr80QJO/qS1P5980yLvqfoYIvsOZyCIFOsgiBpNIoTV9f m7CryAXx/59LLav57dAR3UOL4fEvkSvMp4cQ4QIDAQABo4IC2zCCAtcwCQYDVR0TBAIwADALBgNV HQ8EBAMCBLAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBSypWj+ax4j 6TpWpD4TaRnFP7xJDTAfBgNVHSMEGDAWgBSuVYNv7DHKufcd+q9rMfPIHeOsuzAgBgNVHREEGTAX gRVtYXR0aGV3QG1qZHN5c3RlbXMuY2EwggFMBgNVHSAEggFDMIIBPzCCATsGCysGAQQBgbU3AQID MIIBKjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjCB9wYI KwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRo aXMgY2VydGlmaWNhdGUgd2FzIGlzc3VlZCBhY2NvcmRpbmcgdG8gdGhlIENsYXNzIDIgVmFsaWRh dGlvbiByZXF1aXJlbWVudHMgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25s eSBmb3IgdGhlIGludGVuZGVkIHB1cnBvc2UgaW4gY29tcGxpYW5jZSBvZiB0aGUgcmVseWluZyBw YXJ0eSBvYmxpZ2F0aW9ucy4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5zdGFydHNzbC5j b20vY3J0dTItY3JsLmNybDCBjgYIKwYBBQUHAQEEgYEwfzA5BggrBgEFBQcwAYYtaHR0cDovL29j c3Auc3RhcnRzc2wuY29tL3N1Yi9jbGFzczIvY2xpZW50L2NhMEIGCCsGAQUFBzAChjZodHRwOi8v YWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MyLmNsaWVudC5jYS5jcnQwIwYDVR0SBBww GoYYaHR0cDovL3d3dy5zdGFydHNzbC5jb20vMA0GCSqGSIb3DQEBCwUAA4IBAQBUXPITpbFKhbBF CwTzuTdUc85Q+cB5LGHpUvIdnkvCrBd5KjBOlQP0rheU0PgiBm4NoSRrKCswFDD6ryIsP23gfbAa djhjEj01mbXId3ftn3jBq/6skV+o6V0E1LGGlWK8isHoS5NrjDBNRmI1jMU2TlvP+VwRFa5Ut55h 4CSKMzxG4CB0d+j5riU41O4rJfqidc6pV0zdhpInGHjCu4YVg09bZy5RGtsr+iwOlmHOvR/RAq7l smKdw9e4YR7bltSV4XvuOZdgHjuPIAYlMyX+0m5jy+gj3mOLvFz9VAbR9fGWPNBOTBtfOPmtBkqk rBOTzUomsg1BhU3wau4Pr4cGMYICVTCCAlECAQEwgZMwgYwxCzAJBgNVBAYTAklMMRYwFAYDVQQK Ew1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTaWdu aW5nMTgwNgYDVQQDEy9TdGFydENvbSBDbGFzcyAyIFByaW1hcnkgSW50ZXJtZWRpYXRlIENsaWVu dCBDQQICST4wDQYJYIZIAWUDBAIBBQCggZMwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq hkiG9w0BCQUxDxcNMTYwMTMxMTg1MDM4WjAoBgkqhkiG9w0BCQ8xGzAZMAsGCWCGSAFlAwQBAjAK BggqhkiG9w0DBzAvBgkqhkiG9w0BCQQxIgQgez8VflcmhZEUwHbnbEzUvvfZGuEIAXv4XgsqXz2u qPEwDQYJKoZIhvcNAQEBBQAEggEAhNgnHf6bjv/2L458yAN3spVylmo6fn9hPa0a8j7O73iSvVFg qmVo9uSBbh6KhNplKrtki28hiZNqfA1mvfTfg5KBt81/hmoQHgCQu0qlu0KI33bd7AiKViMz1PDE bTN/YNY5A69qW5Jl4lIZ5gmKdTzwCN866+cFtgG37GPCiJJlrbS6l+1z1xGGswjRcMQBJjb2bXNH nQguEKvvdC0FvU5sEUl+DG6kgQWCjB/+NvnGf89MTSlHSuNRczATz7XETPMqL45zjF8ehbTSYPCM jz9Wbx5zPV7RQeBe+wbKly9RZ5Ne95LVOtUUwDepcWVdmb7v8QBBYKiEf0e5k7UJBAAAAAAAAA== --nextPart46915898.zDM0d8cqMm-- --===============1596145627== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KZHJpLWRldmVs IG1haWxpbmcgbGlzdApkcmktZGV2ZWxAbGlzdHMuZnJlZWRlc2t0b3Aub3JnCmh0dHA6Ly9saXN0 cy5mcmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9kcmktZGV2ZWwK --===============1596145627==--