Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp3711674pxb; Mon, 1 Feb 2021 02:40:51 -0800 (PST) X-Google-Smtp-Source: ABdhPJzUMiFMb/BUTmMBB/xConB4zHxewoaIx10Q72lgB8E3VJD6MvBD0nkB8SwQKxdtO6Jik3pT X-Received: by 2002:aa7:c418:: with SMTP id j24mr5315725edq.293.1612176051395; Mon, 01 Feb 2021 02:40:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1612176051; cv=none; d=google.com; s=arc-20160816; b=fdobMDlQr5Z3oWaIHr5lp13Xyt1j7i/f4FuURolRTULSXe5IlmnqDdsrGWapH1SFr0 G58sWrLudv6s+Z6RtPwGeGiIX0X1dSFsqmnMyMjedaBZJJzBOCknAf+L2OMaGH2dpj4U JMANUnRYt/Ur7D2eVaaieaxD+ylBJrZct+f+NHJDFVgOV5nfOu4P3wvNHpxDShwL8h8e nYAHNeVpCgKUa8mDn3OP5Vk3jbOOOzYT9umLxR2sCfVp3y3kVbBJrRpC0eqITkiMGjdS f0TrQwKEcS4L3vsRzYNz+T8PFgV6EftSTGakXVBtsZXhBa5TtlBLEFeDVDJgNm7a/clL Ivhg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:in-reply-to:date:cc:to :from:subject:message-id:dkim-signature; bh=YLC277Bq47vPy0SNTFpZnU/vn6w0+We0cBtuXXnvfmo=; b=w+xgYJUjukwguoh2M3SvsAjw97xa9CTqN6PRJTWaMw8smJSqr/G1oF6BzAyQ4cg0Pf +yD+OwMgrWukU3bizfXBVf5EV4eNfmBmIRYMUzldq70XNp5fQulsh1du4zTfJd0CmBU3 wm8EaHLo4uLggXIh6ugA1JWG2LTsfdShgFXM5YQ1ZRKqD5M7tZxrcBnJwI4pbFdxlRHl ilNMjDDkd0RyhUtVAYFax0AXCMEPOJbtYyw4NP7DO9QNbARIxnEja+L5KXQQA9WQADx9 HdPzwAmSSPZKiSCkrnJDlIUwRb+ehMYMSpAba5WDMGA5IGu3QePVDCNf2Wp2GIJr0r5r 47/A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@infradead.org header.s=merlin.20170209 header.b=KsxIc2lY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id n20si10267919ejr.520.2021.02.01.02.40.26; Mon, 01 Feb 2021 02:40:51 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@infradead.org header.s=merlin.20170209 header.b=KsxIc2lY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233202AbhBAKhI (ORCPT + 99 others); Mon, 1 Feb 2021 05:37:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233056AbhBAKhE (ORCPT ); Mon, 1 Feb 2021 05:37:04 -0500 Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:8b0:10b:1231::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C122CC061573 for ; Mon, 1 Feb 2021 02:36:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.20170209; h=Mime-Version:Content-Type:References: In-Reply-To:Date:Cc:To:From:Subject:Message-ID:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=YLC277Bq47vPy0SNTFpZnU/vn6w0+We0cBtuXXnvfmo=; b=KsxIc2lYhqbu16svXJyzytkaAA k5IfKnrhyRLCAm8e+RFvZNdSlews3+rgvtQgxGY4P+I66LiPuGQN4jwG+Q5CMoO5zF/uzpNlHIDMZ 1GcE+mUjAFwUMhbroN7HGPvlsu352AuL3uecwKfQAdUmcBUQrObMn34hnxbSHouEFxXmmhNBwpwi7 x81n9Sooe1gFDLHTUS08WEcbHCCWk3u9Ru2Wenis7XFpaeBlxsuSg0b0orvoeaXSg4+UPqleg4+9e dgLmO97VJfkoS9kJLEiWcYnEyYrQLklQV6R8CZ5c5WHMnb117WlKLB76F5i47G7R+BVzB6gVRgDfA viZ/t+EA==; Received: from 54-240-197-234.amazon.com ([54.240.197.234] helo=freeip.amazon.com) by merlin.infradead.org with esmtpsa (Exim 4.92.3 #3 (Red Hat Linux)) id 1l6WZ3-0001SD-Tg; Mon, 01 Feb 2021 10:36:14 +0000 Message-ID: <478c56af540eaa47b8f452e51cb0c085f26db738.camel@infradead.org> Subject: Re: [PATCH] use x86 cpu park to speedup smp_init in kexec situation From: David Woodhouse To: Thomas Gleixner , Andy Lutomirski , "shenkai (D)" , "Schander, Johanna 'Mimoja' Amelie" Cc: LKML , Ingo Molnar , Borislav Petkov , X86 ML , "H. Peter Anvin" , hewenliang4@huawei.com, hushiyuan@huawei.com, luolongjun@huawei.com, hejingxian@huawei.com Date: Mon, 01 Feb 2021 10:36:11 +0000 In-Reply-To: <877do65og8.fsf@nanos.tec.linutronix.de> References: <87eejqu5q5.fsf@nanos.tec.linutronix.de> <8ac72d7b287ed1058b2dec3301578238aff0abdd.camel@infradead.org> <877do65og8.fsf@nanos.tec.linutronix.de> Content-Type: multipart/signed; micalg="sha-256"; protocol="application/x-pkcs7-signature"; boundary="=-lfOdmaUB2mlLFuRQ9bPI" X-Mailer: Evolution 3.28.5-0ubuntu0.18.04.2 Mime-Version: 1.0 X-SRS-Rewrite: SMTP reverse-path rewritten from by merlin.infradead.org. See http://www.infradead.org/rpr.html Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org --=-lfOdmaUB2mlLFuRQ9bPI Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, 2021-01-21 at 15:55 +0100, Thomas Gleixner wrote: > > Here's the hack we're testing with, for reference. It's kind of ugly > > but you can see where it's going. Note that the CMOS mangling for the > > warm reset vector is going to need to be lifted out of the per-cpu > > loop, and done *once* at startup and torn down once in smp_cpus_done. > > Except that it also needs to be done before/after a hotplug cpu up; > > we'll have to come back to that but we've just shifted it to > > native_smp_cpus_done() for testing for now. >=20 > Right. It's at least a start. Here's what we have now. I've refcounted the warm reset vector thing which should fix the hotplug case, although I need to check it gets torn down in the error cases correctly. With the X2APIC global variable thing fixed, the new states can be immediately before CPUHP_BRINGUP_CPU as we originally wanted. I've fixed up the bringup_nonboot_cpus() loop to bring an appropriate number of CPUs to those "CPUHP_BP_PARALLEL_DYN" dynamic parallel pre-bringup states in parallel. We spent a while vacillating about how to add the new states, because of the existing special-case hackery in bringup_cpu() for the CPUHP_BRINGUP_CPU case. The irq_lock_sparse() and the idle_thread_get() from there might actually be needed in *earlier* states for platforms which do parallel bringup.... so do we add similar wrappers in kernel/cpu.c for *all* of the pre-bringup states, having hard-coded them? Then let the arch provide a config symbol for whether it really wants them or not? That seemed kind of horrid, so I went for the simple option of just letting the arch register the CPUHP_BP_PARALLEL_DYN states the normal way with its own functions to be called directly, and the loop in bringup_nonboot_cpus() can then operate directly on whether they exist in the state table or not, for which there is precedent already. That means I needed to export idle_thread_get() for the pre-bringup state functions to use too. I'll also want to add the irq_lock_sparse() into my final patch but frankly, that's the least of my worries about that patch right now. It's also fairly much a no-brainer to splitting up the x86 native_cpu_up() into the four separate phases that I had got separate timings for previously. We can do that just as a "cleanup" with no functional change. So I'm relatively happy at least that far, as preparatory work... David Woodhouse (6): x86/apic/x2apic: Fix parallel handling of cluster_mask cpu/hotplug: Add dynamic states before CPUHP_BRINGUP_CPU for parallel= bringup x86/smpboot: Reference count on smpboot_setup_warm_reset_vector() x86/smpboot: Split up native_cpu_up into separate phases cpu/hotplug: Move idle_thread_get() to arch/x86/kernel/apic/x2apic_cluster.c | 82 +++++++++++++++++------------ arch/x86/kernel/smpboot.c | 159 ++++++++++++++++++++++++++++++= ++++---------------------- include/linux/cpuhotplug.h | 2 + include/linux/smpboot.h | 7 +++ kernel/cpu.c | 27 +++++++++- kernel/smpboot.h | 2 - 6 files changed, 180 insertions(+), 99 deletions(-) That's the generic part mostly done, and the fun part is where we turn back to x86 and actually try to split out those four phases of native_cpu_up() to happen in parallel. We store initial_stack and initial_gs for "the" AP that is coming up, in global variables. It turns out that the APs don't like all sharing the same stack as they come up in parallel, and weird behaviour ensues. I think the only thing the AP has that can disambiguate it from other APs is its CPUID, which it can get in its full 32-bit glory from CPUID.0BH:EDX (and I think we can say we'll do parallel bringup *only* of that leaf exists on the boot CPU). So the trampoline code would need to find the logical CPU# and thus the idle thread stack and per-cpu data with a lookup based on its APICID. Perhaps just by trawling the various per-cpu data until it finds one with the right apicid, much like default_cpu_present_to_apicid() does. Oh, and ideally it needs to do this without using a real-mode stack, because they won't like sharing that *either*. (Actually they don't seem to mind in practice right now because the only thing they all use it for is a 'call verify_cpu' and they all place the *same* return address at the same place on the stack, but it would be horrid to rely on that on *purpose* :) So we'll continue to work on that in order to enable the parallel bringup on x86, unless anyone has any cleverer ideas. After that we'll get to the TSC sync, which is also not working in parallel. --=-lfOdmaUB2mlLFuRQ9bPI Content-Type: application/x-pkcs7-signature; name="smime.p7s" Content-Disposition: attachment; filename="smime.p7s" Content-Transfer-Encoding: base64 MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCCECow ggUcMIIEBKADAgECAhEA4rtJSHkq7AnpxKUY8ZlYZjANBgkqhkiG9w0BAQsFADCBlzELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxPTA7BgNVBAMTNENPTU9ETyBSU0EgQ2xpZW50IEF1dGhl bnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0EwHhcNMTkwMTAyMDAwMDAwWhcNMjIwMTAxMjM1 OTU5WjAkMSIwIAYJKoZIhvcNAQkBFhNkd213MkBpbmZyYWRlYWQub3JnMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAsv3wObLTCbUA7GJqKj9vHGf+Fa+tpkO+ZRVve9EpNsMsfXhvFpb8 RgL8vD+L133wK6csYoDU7zKiAo92FMUWaY1Hy6HqvVr9oevfTV3xhB5rQO1RHJoAfkvhy+wpjo7Q cXuzkOpibq2YurVStHAiGqAOMGMXhcVGqPuGhcVcVzVUjsvEzAV9Po9K2rpZ52FE4rDkpDK1pBK+ uOAyOkgIg/cD8Kugav5tyapydeWMZRJQH1vMQ6OVT24CyAn2yXm2NgTQMS1mpzStP2ioPtTnszIQ Ih7ASVzhV6csHb8Yrkx8mgllOyrt9Y2kWRRJFm/FPRNEurOeNV6lnYAXOymVJwIDAQABo4IB0zCC Ac8wHwYDVR0jBBgwFoAUgq9sjPjF/pZhfOgfPStxSF7Ei8AwHQYDVR0OBBYEFLfuNf820LvaT4AK xrGK3EKx1DE7MA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUF BwMEBggrBgEFBQcDAjBGBgNVHSAEPzA9MDsGDCsGAQQBsjEBAgEDBTArMCkGCCsGAQUFBwIBFh1o dHRwczovL3NlY3VyZS5jb21vZG8ubmV0L0NQUzBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3Js LmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDbGllbnRBdXRoZW50aWNhdGlvbmFuZFNlY3VyZUVtYWls Q0EuY3JsMIGLBggrBgEFBQcBAQR/MH0wVQYIKwYBBQUHMAKGSWh0dHA6Ly9jcnQuY29tb2RvY2Eu Y29tL0NPTU9ET1JTQUNsaWVudEF1dGhlbnRpY2F0aW9uYW5kU2VjdXJlRW1haWxDQS5jcnQwJAYI KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9kb2NhLmNvbTAeBgNVHREEFzAVgRNkd213MkBpbmZy YWRlYWQub3JnMA0GCSqGSIb3DQEBCwUAA4IBAQALbSykFusvvVkSIWttcEeifOGGKs7Wx2f5f45b nv2ghcxK5URjUvCnJhg+soxOMoQLG6+nbhzzb2rLTdRVGbvjZH0fOOzq0LShq0EXsqnJbbuwJhK+ PnBtqX5O23PMHutP1l88AtVN+Rb72oSvnD+dK6708JqqUx2MAFLMevrhJRXLjKb2Mm+/8XBpEw+B 7DisN4TMlLB/d55WnT9UPNHmQ+3KFL7QrTO8hYExkU849g58Dn3Nw3oCbMUgny81ocrLlB2Z5fFG Qu1AdNiBA+kg/UxzyJZpFbKfCITd5yX49bOriL692aMVDyqUvh8fP+T99PqorH4cIJP6OxSTdxKM MIIFHDCCBASgAwIBAgIRAOK7SUh5KuwJ6cSlGPGZWGYwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNV BAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAY BgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMT0wOwYDVQQDEzRDT01PRE8gUlNBIENsaWVudCBBdXRo ZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMB4XDTE5MDEwMjAwMDAwMFoXDTIyMDEwMTIz NTk1OVowJDEiMCAGCSqGSIb3DQEJARYTZHdtdzJAaW5mcmFkZWFkLm9yZzCCASIwDQYJKoZIhvcN AQEBBQADggEPADCCAQoCggEBALL98Dmy0wm1AOxiaio/bxxn/hWvraZDvmUVb3vRKTbDLH14bxaW /EYC/Lw/i9d98CunLGKA1O8yogKPdhTFFmmNR8uh6r1a/aHr301d8YQea0DtURyaAH5L4cvsKY6O 0HF7s5DqYm6tmLq1UrRwIhqgDjBjF4XFRqj7hoXFXFc1VI7LxMwFfT6PStq6WedhROKw5KQytaQS vrjgMjpICIP3A/CroGr+bcmqcnXljGUSUB9bzEOjlU9uAsgJ9sl5tjYE0DEtZqc0rT9oqD7U57My ECIewElc4VenLB2/GK5MfJoJZTsq7fWNpFkUSRZvxT0TRLqznjVepZ2AFzsplScCAwEAAaOCAdMw ggHPMB8GA1UdIwQYMBaAFIKvbIz4xf6WYXzoHz0rcUhexIvAMB0GA1UdDgQWBBS37jX/NtC72k+A CsaxitxCsdQxOzAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEF BQcDBAYIKwYBBQUHAwIwRgYDVR0gBD8wPTA7BgwrBgEEAbIxAQIBAwUwKzApBggrBgEFBQcCARYd aHR0cHM6Ly9zZWN1cmUuY29tb2RvLm5ldC9DUFMwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2Ny bC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQ2xpZW50QXV0aGVudGljYXRpb25hbmRTZWN1cmVFbWFp bENBLmNybDCBiwYIKwYBBQUHAQEEfzB9MFUGCCsGAQUFBzAChklodHRwOi8vY3J0LmNvbW9kb2Nh LmNvbS9DT01PRE9SU0FDbGllbnRBdXRoZW50aWNhdGlvbmFuZFNlY3VyZUVtYWlsQ0EuY3J0MCQG CCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wHgYDVR0RBBcwFYETZHdtdzJAaW5m cmFkZWFkLm9yZzANBgkqhkiG9w0BAQsFAAOCAQEAC20spBbrL71ZEiFrbXBHonzhhirO1sdn+X+O W579oIXMSuVEY1LwpyYYPrKMTjKECxuvp24c829qy03UVRm742R9Hzjs6tC0oatBF7KpyW27sCYS vj5wbal+TttzzB7rT9ZfPALVTfkW+9qEr5w/nSuu9PCaqlMdjABSzHr64SUVy4ym9jJvv/FwaRMP gew4rDeEzJSwf3eeVp0/VDzR5kPtyhS+0K0zvIWBMZFPOPYOfA59zcN6AmzFIJ8vNaHKy5QdmeXx RkLtQHTYgQPpIP1Mc8iWaRWynwiE3ecl+PWzq4i+vdmjFQ8qlL4fHz/k/fT6qKx+HCCT+jsUk3cS jDCCBeYwggPOoAMCAQICEGqb4Tg7/ytrnwHV2binUlYwDQYJKoZIhvcNAQEMBQAwgYUxCzAJBgNV BAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAY BgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYDVQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRp b24gQXV0aG9yaXR5MB4XDTEzMDExMDAwMDAwMFoXDTI4MDEwOTIzNTk1OVowgZcxCzAJBgNVBAYT AkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNV BAoTEUNPTU9ETyBDQSBMaW1pdGVkMT0wOwYDVQQDEzRDT01PRE8gUlNBIENsaWVudCBBdXRoZW50 aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAvrOeV6wodnVAFsc4A5jTxhh2IVDzJXkLTLWg0X06WD6cpzEup/Y0dtmEatrQPTRI5Or1u6zf +bGBSyD9aH95dDSmeny1nxdlYCeXIoymMv6pQHJGNcIDpFDIMypVpVSRsivlJTRENf+RKwrB6vcf WlP8dSsE3Rfywq09N0ZfxcBa39V0wsGtkGWC+eQKiz4pBZYKjrc5NOpG9qrxpZxyb4o4yNNwTqza aPpGRqXB7IMjtf7tTmU2jqPMLxFNe1VXj9XB1rHvbRikw8lBoNoSWY66nJN/VCJv5ym6Q0mdCbDK CMPybTjoNCQuelc0IAaO4nLUXk0BOSxSxt8kCvsUtQIDAQABo4IBPDCCATgwHwYDVR0jBBgwFoAU u69+Aj36pvE8hI6t7jiY7NkyMtQwHQYDVR0OBBYEFIKvbIz4xf6WYXzoHz0rcUhexIvAMA4GA1Ud DwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBEGA1UdIAQKMAgwBgYEVR0gADBMBgNVHR8E RTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9u QXV0aG9yaXR5LmNybDBxBggrBgEFBQcBAQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29t b2RvY2EuY29tL0NPTU9ET1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz cC5jb21vZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAHhcsoEoNE887l9Wzp+XVuyPomsX9vP2 SQgG1NgvNc3fQP7TcePo7EIMERoh42awGGsma65u/ITse2hKZHzT0CBxhuhb6txM1n/y78e/4ZOs 0j8CGpfb+SJA3GaBQ+394k+z3ZByWPQedXLL1OdK8aRINTsjk/H5Ns77zwbjOKkDamxlpZ4TKSDM KVmU/PUWNMKSTvtlenlxBhh7ETrN543j/Q6qqgCWgWuMAXijnRglp9fyadqGOncjZjaaSOGTTFB+ E2pvOUtY+hPebuPtTbq7vODqzCM6ryEhNhzf+enm0zlpXK7q332nXttNtjv7VFNYG+I31gnMrwfH M5tdhYF/8v5UY5g2xANPECTQdu9vWPoqNSGDt87b3gXb1AiGGaI06vzgkejL580ul+9hz9D0S0U4 jkhJiA7EuTecP/CFtR72uYRBcunwwH3fciPjviDDAI9SnC/2aPY8ydehzuZutLbZdRJ5PDEJM/1t yZR2niOYihZ+FCbtf3D9mB12D4ln9icgc7CwaxpNSCPt8i/GqK2HsOgkL3VYnwtx7cJUmpvVdZ4o gnzgXtgtdk3ShrtOS1iAN2ZBXFiRmjVzmehoMof06r1xub+85hFQzVxZx5/bRaTKTlL8YXLI8nAb R9HWdFqzcOoB/hxfEyIQpx9/s81rgzdEZOofSlZHynoSMYIDyjCCA8YCAQEwga0wgZcxCzAJBgNV BAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAY BgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMT0wOwYDVQQDEzRDT01PRE8gUlNBIENsaWVudCBBdXRo ZW50aWNhdGlvbiBhbmQgU2VjdXJlIEVtYWlsIENBAhEA4rtJSHkq7AnpxKUY8ZlYZjANBglghkgB ZQMEAgEFAKCCAe0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjEw MjAxMTAzNjExWjAvBgkqhkiG9w0BCQQxIgQghkNMVX6Xl2tPbPyRySmz1FUlPoFbSloYHMqmdcZ1 FDEwgb4GCSsGAQQBgjcQBDGBsDCBrTCBlzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIg TWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQx PTA7BgNVBAMTNENPTU9ETyBSU0EgQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1h aWwgQ0ECEQDiu0lIeSrsCenEpRjxmVhmMIHABgsqhkiG9w0BCRACCzGBsKCBrTCBlzELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxPTA7BgNVBAMTNENPTU9ETyBSU0EgQ2xpZW50IEF1dGhl bnRpY2F0aW9uIGFuZCBTZWN1cmUgRW1haWwgQ0ECEQDiu0lIeSrsCenEpRjxmVhmMA0GCSqGSIb3 DQEBAQUABIIBAJEwDLMHQkhmc2EHL5bgsotPl+HdABPpjMjuRmnadfI4g+Z/DVeQP8eUrs7kzcqN 2p5TqVXhAZhU78rBFCoePRlAFXJYyiJ1qYCuQPTXpRFDyu5HJe1vP/nuK8G9eQRnBEo24lmfmGMQ yfsxAF+/307lXdrT8YNS1RoTMfAg5PrMsU5vp3vsLiWhHiD/brknyxUTCPEVgXCzvFSCFsVkqG6z bjbVncD/LvSoSA8Wmx5VAmOm9Zvvs/pN5a7iOhfdPloc7b+4LV7oq5BrYaeUn+kD9fmmfONdr/Cj +LyBbQJrKJmYz3cfGc55yNAoXz1FxFdm7Pgv+KS9vW5Y0zBTS00AAAAAAAA= --=-lfOdmaUB2mlLFuRQ9bPI--