From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Subject: [RFC,1/2] drivers/edac: Add L1 and L2 error detection for A53 and A57 From: James Morse Message-Id: <5AAA7640.3010506@arm.com> Date: Thu, 15 Mar 2018 13:33:52 +0000 To: York Sun Cc: bp@alien8.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, "linux-arm-kernel@lists.infradead.org" List-ID: SGkgWW9yaywKCllvdSBoYXZlIGEgRFQgYmluZGluZyBpbiBoZXJlLCBwbGVhc2UgQ0MgdGhlIGRl dmljZXRyZWUgbGlzdC4gWW91J3JlIHRvdWNoaW5nCmNvZGUgdW5kZXIgYXJjaC9hcm02NCwgc28g eW91IG5lZWQgdGhlIGFybSBsaXN0IHRvby4gZ2V0X21haW50YWluZXIucGwgd2lsbCB0YWtlCnlv dXIgcGF0Y2ggYW5kIGdpdmUgeW91IHRoZSBsaXN0IG9mIHdoaWNoIGxpc3RzIGFuZCBtYWludGFp bmVycyB0byBDQy4KCihJJ3ZlIGFkZGVkIHRob3NlIGxpc3RzLCB0aGUgZnVsbCBwYXRjaCBpcyBo ZXJlOgpodHRwczovL3BhdGNod29yay5rZXJuZWwub3JnL3BhdGNoLzEwMjgzNzgzLwopCgpTb21l IGNvbW1lbnRzIGJlbG93LCBJIGhhdmVuJ3QgbG9va2VkIGluIHRvIGVkYWMgb3IgdGhlIG1hbnVh bHMgZm9yIEE1My9BNTcuCgpPbiAxNS8wMy8xOCAwMDoxNywgWW9yayBTdW4gd3JvdGU6Cj4gQWRk IGVycm9yIGRldGVjdGlvbiBmb3IgQTUzIGFuZCBBNTcgY29yZXMuIEhhcmR3YXJlIGVycm9yIGlu amVjdGlvbgo+IGlzIHN1cHBvcnRlZCBvbiBBNTMuIFNvZnR3YXJlIGVycm9yIGluamVjdGlvbiBp cyBzdXBwb3J0ZWQgb24gYm90aC4KPiBGb3IgaGFyZHdhcmUgZXJyb3IgaW5qZWN0aW9uIG9uIEE1 MyB0byB3b3JrLCBwcm9wZXIgYWNjZXNzIHRvCj4gTDJBQ1RMUl9FTDEsIENQVUFDVExSX0VMMSBu ZWVkcyB0byBiZSBncmFudGVkIGJ5IEVMMyBmaXJtd2FyZS4gVGhpcwo+IGlzIGRvbmUgYnkgbWFr aW5nIGFuIFNNQyBjYWxsIGluIHRoZSBkcml2ZXIuIEZhaWx1cmUgdG8gZW5hYmxlIGFjY2Vzcwo+ IGRpc2FibGVzIGhhcmR3YXJlIGVycm9yIGluamVjdGlvbi4gRm9yIGVycm9yIGludGVycnVwdCB0 byB3b3JrLAo+IGFub3RoZXIgU01DIGNhbGwgZW5hYmxlcyBhY2Nlc3MgdG8gTDJFQ1RMUl9FTDEu IEZhaWx1cmUgdG8gZW5hYmxlCj4gYWNjZXNzIGRpc2FibGVzIGludGVycnVwdCBmb3IgZXJyb3Ig cmVwb3J0aW5nLgoKVGhpcyBpcyB0cmlja3kgYXMgdGhlcmUgYXJlIHNoaXBwZWQgc3lzdGVtcyBv dXQgdGhlcmUgd2l0aG91dCB0aGVzZSBTTUMgY2FsbHMuClRoZXkgbmVlZCB0byBiZSBkaXNjb3Zl cmVkIGluIHNvbWUgd2F5LiBXZSBjYW4ndCBldmVuIGFzc3VtZSBmaXJtd2FyZSBoYXMgUFNDSSwK aXQgaGFzIHRvIGJlIGRpc2NvdmVyZWQgdmlhIEFQQ0kvRFQuCgpJIHRoaW5rIGl0IHdpbGwgYmUg Y2xlYW5lciBmb3IgdGhlIHByZXNlbmNlIG9mIHRoaXMgZGV2aWNlL2NvbXBhdGlibGUgdG8KaW5k aWNhdGUgdGhhdCB0aGUgcmVnaXN0ZXJzIGFyZSBlbmFibGVkIGZvciB0aGUgbm9ybWFsLXdvcmxk LCBpbnN0ZWFkIG9mIGhhdmluZwp0aGUgT1MgdHJ5IHRvIGNhbGwgaW50byBmaXJtd2FyZSB0byBl bmFibGUgaXQuCgoKPiBTaWduZWQtb2ZmLWJ5OiBZb3JrIFN1biA8eW9yay5zdW5AbnhwLmNvbT4K PiAtLS0KPiAgLi4uL2RldmljZXRyZWUvYmluZGluZ3MvZWRhYy9jb3J0ZXgtYXJtNjQtZWRhYy50 eHQgfCAgMzcgKwo+ICBhcmNoL2FybTY0L2luY2x1ZGUvYXNtL2NhY2hlZmx1c2guaCAgICAgICAg ICAgICAgICB8ICAgMSArCj4gIGFyY2gvYXJtNjQvbW0vY2FjaGUuUyAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgIHwgIDM1ICsKPiAgZHJpdmVycy9lZGFjL0tjb25maWcgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgfCAgIDYgKwo+ICBkcml2ZXJzL2VkYWMvTWFrZWZpbGUgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICB8ICAgMSArCj4gIGRyaXZlcnMvZWRhYy9jb3J0ZXhfYXJt NjRfbDFfbDIuYyAgICAgICAgICAgICAgICAgIHwgNzQxICsrKysrKysrKysrKysrKysrKysrKwo+ ICBkcml2ZXJzL2VkYWMvY29ydGV4X2FybTY0X2wxX2wyLmggICAgICAgICAgICAgICAgICB8ICA1 NSArKwo+ICA3IGZpbGVzIGNoYW5nZWQsIDg3NiBpbnNlcnRpb25zKCspCj4gIGNyZWF0ZSBtb2Rl IDEwMDY0NCBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZWRhYy9jb3J0ZXgtYXJt NjQtZWRhYy50eHQKPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZWRhYy9jb3J0ZXhfYXJt NjRfbDFfbDIuYwo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9lZGFjL2NvcnRleF9hcm02 NF9sMV9sMi5oCj4gCj4gZGlmZiAtLWdpdCBhL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5k aW5ncy9lZGFjL2NvcnRleC1hcm02NC1lZGFjLnR4dCBiL0RvY3VtZW50YXRpb24vZGV2aWNldHJl ZS9iaW5kaW5ncy9lZGFjL2NvcnRleC1hcm02NC1lZGFjLnR4dAo+IG5ldyBmaWxlIG1vZGUgMTAw NjQ0Cj4gaW5kZXggMDAwMDAwMC4uNzRhMWMyZgo+IC0tLSAvZGV2L251bGwKPiArKysgYi9Eb2N1 bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZWRhYy9jb3J0ZXgtYXJtNjQtZWRhYy50eHQK PiBAQCAtMCwwICsxLDM3IEBACj4gK0FSTSBDb3J0ZXggQTU3IGFuZCBBNTMgTDEvTDIgY2FjaGUg ZXJyb3IgcmVwb3J0aW5nCj4gKwo+ICtDUFUgTWVtb3J5IEVycm9yIFN5bmRyb21lIGFuZCBMMiBN ZW1vcnkgRXJyb3IgU3luZHJvbWUgcmVnaXN0ZXJzIGNhbiBiZSB1c2VkCj4gK2ZvciBjaGVja2lu ZyBMMSBhbmQgTDIgbWVtb3J5IGVycm9ycy4gSG93ZXZlciwgb25seSBBNTMgc3VwcG9ydHMgZG91 YmxlLWJpdAo+ICtlcnJvciBpbmplY3Rpb24gdG8gTDEgYW5kIEwyIG1lbW9yeS4gVGhpcyBkcml2 ZXIgdXNlcyB0aGUgaGFyZHdhcmUgZXJyb3IKPiAraW5qZWN0aW9uIHdoZW4gYXZhaWxhYmxlLCBi dXQgYWxzbyBwcm92aWRlcyBhIHdheSB0byBpbmplY3QgZXJyb3JzIGJ5Cj4gK3NvZnR3YXJlLiBC b3RoIEE1MyBhbmQgQTU3IHN1cHBvcnRzIGludGVycnVwdCB3aGVuIG11bHRpLWJpdCBlcnJvcnMg aGFwcGVuLgoKPiArVG8gdXNlIGhhcmR3YXJlIGVycm9yIGluamVjdGlvbiBhbmQgdGhlIGludGVy cnVwdCwgcHJvcGVyIGFjY2VzcyBuZWVkcyB0byBiZQo+ICtncmFudGVkIGluIEFDVExSX0VMMyAo YW5kL29yIEFDVExSX0VMMikgcmVnaXN0ZXIgYnkgRUwzIGZpcm13YXJlIFNNQyBjYWxsLgoKSG93 IGNhbiBMaW51eCBrbm93IHdoZXRoZXIgZmlybXdhcmUgdG9nZ2xlZCB0aGVzZSBiaXRzPyBIb3cg Y2FuIGl0IGtub3cgaWYgaXQKbmVlZHMgdG8gbWFrZSBhbiBTTUMgY2FsbCB0byBkbyB0aGUgd29y az8KClRoaXMgbG9va3MgbGlrZSBwbGF0Zm9ybSBwb2xpY3ksIEknbSBub3Qgc3VyZSBob3cgdGhp cyBnZXRzIGRlc2NyaWJlZC4uLgoKCj4gK0NvcnJlY3RhYmxlIGVycm9ycyBkbyBub3QgdHJpZ2dl ciBzdWNoIGludGVycnVwdC4gVGhpcyBkcml2ZXIgdXNlcyBkeW5hbWljCj4gK3BvbGxpbmcgaW50 ZXJuYWwgdG8gY2hlY2sgZm9yIGVycm9ycy4gVGhlIG1vcmUgZXJyb3JzIGRldGVjdGVkLCB0aGUg bW9yZQo+ICtmcmVxdWVudGx5IGl0IHBvbGxzLiBDb21iaW5pbmcgd2l0aCBpbnRlcnJ1cHQsIHRo aXMgZHJpdmVyIGNhbiBkZXRlY3QKPiArY29ycmVjdGFibGUgYW5kIHVuY29ycmVjdGFibGUgZXJy b3JzLiBIb3dldmVyLCBpZiB0aGUgdW5jb3JyZWN0YWJsZSBlcnJvcnMKPiArY2F1c2Ugc3lzdGVt IGFib3J0IGV4Y2VwdGlvbiwgdGhpcyBkcml2ciBpcyBub3QgYWJsZSB0byByZXBvcnQgZXJyb3Jz IGluIHRpbWUuCj4gKwo+ICtUaGUgZm9sbG93aW5nIHNlY3Rpb24gZGVzY3JpYmVzIHRoZSBDb3J0 ZXggQTU3L0E1MyBFREFDIERUIG5vZGUgYmluZGluZy4KPiArCj4gK1JlcXVpcmVkIHByb3BlcnRp ZXM6Cj4gKy0gY29tcGF0aWJsZTogU2hvdWxkIGJlICJhcm0sY29ydGV4LWE1Ny1lZGFjIiBvciAi YXJtLGNvcnRleC1hNTMtZWRhYyIKPiArLSBjcHVzOiBTaG91bGQgYmUgYSBsaXN0IG9mIGNvbXBh dGlibGUgY29yZXMKPiArCj4gK09wdGlvbmFsIHByb3BlcnRpZXM6Cj4gKy0gaW50ZXJydXB0czog SW50ZXJydXB0IG51bWJlciBpZiBzdXBwb3J0ZWQKPiArCj4gK0V4YW1wbGU6Cj4gKwllZGFjIHsK PiArCQljb21wYXRpYmxlID0gImFybSxjb3J0ZXgtYTUzLWVkYWMiOwo+ICsJCWNwdXMgPSA8JmNw dTA+LAo+ICsJCSAgICAgICA8JmNwdTE+LAo+ICsJCSAgICAgICA8JmNwdTI+LAo+ICsJCSAgICAg ICA8JmNwdTM+Owo+ICsJCWludGVycnVwdHMgPSA8MCAxMDggMHg0PjsKPiArCj4gKwl9Owo+ICsK Cj4gZGlmZiAtLWdpdCBhL2FyY2gvYXJtNjQvaW5jbHVkZS9hc20vY2FjaGVmbHVzaC5oIGIvYXJj aC9hcm02NC9pbmNsdWRlL2FzbS9jYWNoZWZsdXNoLmgKPiBpbmRleCA3NmQxY2M4Li5mMWNkMDkw IDEwMDY0NAo+IC0tLSBhL2FyY2gvYXJtNjQvaW5jbHVkZS9hc20vY2FjaGVmbHVzaC5oCj4gKysr IGIvYXJjaC9hcm02NC9pbmNsdWRlL2FzbS9jYWNoZWZsdXNoLmgKPiBAQCAtNzMsNiArNzMsNyBA QCBleHRlcm4gdm9pZCBfX2NsZWFuX2RjYWNoZV9hcmVhX3BvcCh2b2lkICphZGRyLCBzaXplX3Qg bGVuKTsKPiAgZXh0ZXJuIHZvaWQgX19jbGVhbl9kY2FjaGVfYXJlYV9wb3Uodm9pZCAqYWRkciwg c2l6ZV90IGxlbik7Cj4gIGV4dGVybiBsb25nIF9fZmx1c2hfY2FjaGVfdXNlcl9yYW5nZSh1bnNp Z25lZCBsb25nIHN0YXJ0LCB1bnNpZ25lZCBsb25nIGVuZCk7Cj4gIGV4dGVybiB2b2lkIHN5bmNf aWNhY2hlX2FsaWFzZXModm9pZCAqa2FkZHIsIHVuc2lnbmVkIGxvbmcgbGVuKTsKPiArZXh0ZXJu IHZvaWQgX19mbHVzaF9sMV9kY2FjaGVfd2F5KHBoeXNfYWRkcl90IHB0cik7Cj4gIAo+ICBzdGF0 aWMgaW5saW5lIHZvaWQgZmx1c2hfY2FjaGVfbW0oc3RydWN0IG1tX3N0cnVjdCAqbW0pCj4gIHsK Cj4gZGlmZiAtLWdpdCBhL2FyY2gvYXJtNjQvbW0vY2FjaGUuUyBiL2FyY2gvYXJtNjQvbW0vY2Fj aGUuUwo+IGluZGV4IDdmMWRiZTkuLjVlNjVjMjAgMTAwNjQ0Cj4gLS0tIGEvYXJjaC9hcm02NC9t bS9jYWNoZS5TCj4gKysrIGIvYXJjaC9hcm02NC9tbS9jYWNoZS5TCj4gQEAgLTIyMSwzICsyMjEs MzggQEAgRU5UUlkoX19kbWFfdW5tYXBfYXJlYSkKPiAgCWIubmUJX19kbWFfaW52X2FyZWEKPiAg CXJldAo+ICBFTkRQSVBST0MoX19kbWFfdW5tYXBfYXJlYSkKPiArCj4gKy8qCj4gKyAqCUZsdXNo IEwxIGRjYWNoZSBieSB3YXksIHVzaW5nIHBoeXNpY2FsIGFkZHJlc3MgdG8gZmluZCBzZXRzCj4g KyAqCj4gKyAqCV9fZmx1c2hfbDFfZGNhY2hlX3dheShwdHIpCj4gKyAqCS0gcHRyCS0gcGh5c2lj YWwgYWRkcmVzcyB0byBiZSBmbHVzaGVkCj4gKyAqLwoKV2UgZG9uJ3QgaGF2ZSBzZXQvd2F5IG1h aW50ZW5hbmNlIGluIHRoZSBrZXJuZWwgYmVjYXVzZSBpdHMgaW1wb3NzaWJsZSB0byBkbwpjb3Jy ZWN0bHkgb3V0c2lkZSBFTDMncyBDUFUgcG93ZXItb24gY29kZS4KClRoZSBBUk0tQVJNIGhhcyBh IGhhbGYgcGFnZSAnbm90ZScgZXhwbGFpbmluZyB0aGUgaXNzdWVzLCB1bmRlciAnUGVyZm9ybWlu ZwpjYWNoZSBtYWludGVuYW5jZSBpbnN0cnVjdGlvbnMnIGluIHNlY3Rpb24gIkQzLjQuOCBBNjQg Q2FjaGUgbWFpbnRlbmFuY2UKaW5zdHJ1Y3Rpb25zIi4gSWYgeW91IGhhdmUgRERJMDQ4N0IuYiwg aXRzIG9uIFBhZ2UgRDMtMjAyMC4KClRoZXNlIG1heSBhbHNvIGhlbHA6Cmh0dHBzOi8vbGttbC5v cmcvbGttbC8yMDE2LzMvMjEvMTkwCmh0dHBzOi8vZXZlbnRzLnN0YXRpYy5saW51eGZvdW5kLm9y Zy9zaXRlcy9ldmVudHMvZmlsZXMvc2xpZGVzL3NsaWRlc18xNy5wZGYKaHR0cHM6Ly93d3cubGlu dXguY29tL25ld3MvdGFtaW5nLWNoYW9zLW1vZGVybi1jYWNoZXMKCldoeSBkbyB5b3UgbmVlZCB0 byBkbyB0aGlzPyBUaGVyZSBpcyBubyB3YXkgdG8gZ3VhcmFudGVlIGFuIGFkZHJlc3MgaXNuJ3Qg aW4gdGhlCmNhY2hlLgoKCj4gK0VOVFJZKF9fZmx1c2hfbDFfZGNhY2hlX3dheSkKPiArCW1zcglj c3NlbHJfZWwxLCB4enIJCS8qIHNlbGVjdCBjYWNoZSBsZXZlbCAxICovCj4gKwlpc2IKPiArCW1y cwl4NiwgY2NzaWRyX2VsMQo+ICsJYW5kCXgyLCB4NiwgIzcKPiArCWFkZAl4MiwgeDIsICM0CQkv KiB4MiBoYXMgbG9nMihjYWNoZSBsaW5lIHNpemUpICovCj4gKwltb3YJeDMsICMweDNmZgo+ICsJ YW5kCXgzLCB4MywgeDYsIGxzciAjMwkvKiB4MyBoYXMgbnVtYmVyIG9mIHdheXMgLSAxICovCj4g KwljbHoJdzUsIHczCQkJLyogYml0IHBvc2l0aW9uIG9mIHdheXMgKi8KPiArCW1vdgl4NCwgIzB4 N2ZmZgo+ICsJYW5kCXg0LCB4NCwgeDYsIGxzciAjMTMJLyogeDQgaGFzIG51bWJlciBvZiBzZXRz IC0gMSAqLwo+ICsJY2x6CXg3LCB4NAo+ICsJbHNyCXgwLCB4MCwgeDIKPiArCWxzbAl4MCwgeDAs IHg3Cj4gKwlsc3IJeDAsIHgwLCB4NwkJLyogeDAgaGFzIHRoZSBzZXQgZm9yIHB0ciAqLwo+ICsK PiArCW1vdgl4NiwgeDMKPiArbG9vcF93YXk6Cj4gKwlsc2wJeDksIHgzLCB4NQo+ICsJbHNsCXg3 LCB4MCwgeDIKPiArCW9ycgl4OSwgeDksIHg3Cj4gKwlkYwljaXN3LCB4OQo+ICsJc3Vicwl4Niwg eDYsICMxCj4gKwliLmdlCWxvb3Bfd2F5Cj4gKwlkc2IJaXNoCj4gKwlyZXQKPiArCj4gK0VORFBJ UFJPQyhfX2ZsdXNoX2wxX2RjYWNoZV93YXkpCgoKPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9lZGFj L01ha2VmaWxlIGIvZHJpdmVycy9lZGFjL01ha2VmaWxlCj4gaW5kZXggMGZkOWZmYS4uNmMyMTk0 MSAxMDA2NDQKPiAtLS0gYS9kcml2ZXJzL2VkYWMvTWFrZWZpbGUKPiArKysgYi9kcml2ZXJzL2Vk YWMvTWFrZWZpbGUKPiBAQCAtNzgsMyArNzgsNCBAQCBvYmotJChDT05GSUdfRURBQ19USFVOREVS WCkJCSs9IHRodW5kZXJ4X2VkYWMubwo+ICBvYmotJChDT05GSUdfRURBQ19BTFRFUkEpCQkrPSBh bHRlcmFfZWRhYy5vCj4gIG9iai0kKENPTkZJR19FREFDX1NZTk9QU1lTKQkJKz0gc3lub3BzeXNf ZWRhYy5vCj4gIG9iai0kKENPTkZJR19FREFDX1hHRU5FKQkJKz0geGdlbmVfZWRhYy5vCj4gK29i ai0kKENPTkZJR19FREFDX0NPUlRFWF9BUk02NF9MMV9MMikJKz0gY29ydGV4X2FybTY0X2wxX2wy Lm8KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9lZGFjL2NvcnRleF9hcm02NF9sMV9sMi5jIGIvZHJp dmVycy9lZGFjL2NvcnRleF9hcm02NF9sMV9sMi5jCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiBp bmRleCAwMDAwMDAwLi45YmNjOGU5Cj4gLS0tIC9kZXYvbnVsbAo+ICsrKyBiL2RyaXZlcnMvZWRh Yy9jb3J0ZXhfYXJtNjRfbDFfbDIuYwo+IEBAIC0wLDAgKzEsNzQxIEBACj4gKy8qCj4gKyAqIENv cnRleCBBNTcgYW5kIEE1MyBFREFDIEwxIGFuZCBMMiBjYWNoZSBlcnJvciBkZXRlY3Rpb24KPiAr ICoKPiArICogQ29weXJpZ2h0IChjKSAyMDE4LCBOWFAgU2VtaWNvbmR1Y3Rvcgo+ICsgKiBBdXRo b3I6IFlvcmsgU3VuIDx5b3JrLnN1bkBueHAuY29tPgo+ICsgKgo+ICsgKiBQYXJ0aWFsbHkgdGFr ZSBmcm9tIGEgc2ltaWxhciBkcml2ZXIgYnkKPiArICogQnJpamVzaCBTaW5naCA8YnJpamVzaGt1 bWFyLnNpbmdoQGFtZC5jb20+Cj4gKyAqIENvcHlyaWdodCAoYykgMjAxNSwgQWR2YW5jZWQgTWlj cm8gRGV2aWNlcwo+ICsgKgo+ICsgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMAo+ ICsgKi8KPiArCj4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4KPiArI2luY2x1ZGUgPGxpbnV4 L29mX3BsYXRmb3JtLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9vZl9kZXZpY2UuaD4KPiArI2luY2x1 ZGUgPGxpbnV4L2FybS1zbWNjYy5oPgo+ICsjaW5jbHVkZSA8YXNtL2JhcnJpZXIuaD4KPiArI2lu Y2x1ZGUgPGFzbS9jYWNoZWZsdXNoLmg+Cj4gKyNpbmNsdWRlIDxhc20vc21wX3BsYXQuaD4KPiAr Cj4gKyNpbmNsdWRlICJlZGFjX21vZHVsZS5oIgo+ICsjaW5jbHVkZSAiY29ydGV4X2FybTY0X2wx X2wyLmgiCj4gKwo+ICtzdGF0aWMgaW50IHBvbGxfbXNlYyA9IDEwMjQ7Cj4gK3N0YXRpYyBsb25n IGwxX2NlX3N3X2luamVjdF9jb3VudCwgbDFfdWVfc3dfaW5qZWN0X2NvdW50Owo+ICtzdGF0aWMg bG9uZyBsMl9jZV9zd19pbmplY3RfY291bnQsIGwyX3VlX3N3X2luamVjdF9jb3VudDsKPiArc3Rh dGljIHN0cnVjdCBjcHVtYXNrIGNvbXBhdF9tYXNrOwo+ICtzdGF0aWMgc3RydWN0IGNwdW1hc2sg bDFfY2VfY3B1X21hc2ssIGwxX3VlX2NwdV9tYXNrOwo+ICtzdGF0aWMgc3RydWN0IGNwdW1hc2sg bDJfY2VfY3B1X21hc2ssIGwyX3VlX2NwdV9tYXNrOwo+ICtzdGF0aWMgREVGSU5FX1BFUl9DUFUo dW5zaWduZWQgbG9uZywgYWN0bHJfZW4pOwo+ICtzdGF0aWMgREVGSU5FX1BFUl9DUFUodW5zaWdu ZWQgbG9uZywgbDJlY3Rscl9lbik7Cj4gK3N0YXRpYyBERUZJTkVfUEVSX0NQVSh1NjQsIGNwdW1l cnIpOwo+ICtzdGF0aWMgREVGSU5FX1BFUl9DUFUodTY0LCBjcHVhY3Rscik7Cj4gK3N0YXRpYyBE RUZJTkVfUEVSX0NQVSh1NjQsIGwyYWN0bHIpOwo+ICtzdGF0aWMgREVGSU5FX1BFUl9DUFUodTY0 LCBsMm1lcnIpOwo+ICtzdGF0aWMgREVGSU5FX1BFUl9DUFUoY2FsbF9zaW5nbGVfZGF0YV90LCBj c2RfY2hlY2spOwo+ICtzdGF0aWMgREVGSU5FX1NQSU5MT0NLKGNvcnRleF9lZGFjX2xvY2spOwo+ ICsKPiArc3RhdGljIGlubGluZSB2b2lkIHJlYWRfY3B1YWN0bHIodm9pZCAqaW5mbykKPiArewo+ ICsJdTY0IHZhbDsKPiArCWludCBjcHUgPSBzbXBfcHJvY2Vzc29yX2lkKCk7Cj4gKwo+ICsJYXNt IHZvbGF0aWxlKCJtcnMgJTAsIFMzXzFfQzE1X0MyXzAiIDogIj1yIiAodmFsKSk7CgpJIG1ha2Ug QUNUTFJfRUwxJ3MgZW5jb2RpbmcgUzNfMF8xXzBfMS4gV2hhdCdzIHRoaXMgdGhpbmc/CgpQbGVh c2UgY3JlYXRlIGEgZGVmaW5lIGluIHlvdXIgZHJpdmVyIGZvciB0aGVzZSByZWdpc3RlcnMgYW5k IHVzZSB0aGUKcmVhZF9zeXNyZWdfcygpIGhlbHBlcnMuIGUuZzoKfCAjZGVmaW5lIEE1M19TWVNf U09NRVRISU5HX0VMMQkJc3lzX3JlZygzLCAxLCAxNSwgMiwgMCkKfCB2YWwgPSByZWFkX3N5c3Jl Z19zKEE1M19TWVNfU09NRVRISU5HX0VMMSk7CgoKCj4gKwlwZXJfY3B1KGNwdWFjdGxyLCBjcHUp ID0gdmFsOwoKdGhpc19jcHVfd3JpdGUoKSA/CgoKPiArfQo+ICsKPiArc3RhdGljIGlubGluZSB2 b2lkIHdyaXRlX2NwdWFjdGxyKGludCAqbWVtKQo+ICt7Cj4gKwl1NjQgdmFsOwo+ICsJaW50IGNw dTsKPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJmNv cnRleF9lZGFjX2xvY2ssIGZsYWdzKTsKPiArCWNwdSA9IHNtcF9wcm9jZXNzb3JfaWQoKTsKPiAr Cj4gKwlfX2ZsdXNoX2RjYWNoZV9hcmVhKG1lbSwgOCk7CgpXaGF0IGlzIDg/CgoKPiArCWFzbSB2 b2xhdGlsZSgibXJzICUwLCBTM18xX0MxNV9DMl8wIiA6ICI9ciIgKHZhbCkpOwo+ICsJdmFsIHw9 IEwxX0VSUl9JTkpfRU47Cj4gKwlhc20gdm9sYXRpbGUoImRzYiBzeSIpOwo+ICsJYXNtIHZvbGF0 aWxlKCJtc3IgUzNfMV9DMTVfQzJfMCwgJTAiIDo6ICJyIiAodmFsKSk7Cj4gKwlhc20gdm9sYXRp bGUoImlzYiBzeSIpOwoKUGxlYXNlIHVzZSB0aGUgbWFjcm9zLCB0aGV5J3JlIGJldHRlciB0aGFu IHRoaXMgYXNtLXZvbGF0aWxlOgp8IGRzYihzeSk7CnwgaXNiKCk7CgouLi5hbmQsIHRoZXkgd2ls bCBhbHNvIGdpdmUgeW91IHRoZSBjb21waWxlciBiYXJyaWVyIHlvdSB3YW50IGhlcmUuLi4KCgo+ ICsJLyogbWFrZSBjYWNoZSBkaXJ0eSAqLwo+ICsJKm1lbSA9IDB4REVBREJFRUY7CS8qIHdyaXRl IHRvIEwxIGRhdGEgY2F1c2VzIGVycm9yIHJpZ2h0IGF3YXkgKi8KCllvdSdyZSBkb2luZyB0aGlz IGluIEMgY29kZS4gVGhlIGNvbXBpbGVyIGlzIGFsbG93ZWQgdG8gcmUtb3JkZXIgdGhpcyB3cml0 ZS4gQXMKeW91IGRvbid0IHJlYWQgKm1lbSwgaXQgY2FuIHB1dCBpdCBhbnl3aGVyZSBiZXR3ZWVu CnNwaW5fbG9ja19pcnFzYXZlKCkvc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgpLiBJdCBjYW4gZXZl biBkbyBpdCBpbiB0d28gaGFsdmVzLApvciBkbyBpdCB0d2ljZSBpZiBpdCB3YW50cyB0by4KCldS SVRFX09OQ0UoKSB0ZWxscyB0aGUgY29tcGlsZXIgbm90IHNwbGl0IHRoaXMgd3JpdGUgdXAsIGFu ZCB5b3UgbmVlZCBjb21waWxlcgpiYXJyaWVycyBhcyB3ZWxsIGFzIHRoZSBDUFUgaW5zdHJ1Y3Rp b24gYmFycmllcnMgeW91IGhhdmUuIFRoZSBjb21waWxlciBkb2Vzbid0Cmtub3cgd2hhdCAnaXNi JyBtZWFucy4gKHRoaXMgaXMgd2h5IHdlIGFscmVhZHkgaGF2ZSB0aG9zZSBtYWNyb3MpCgpCdXQh IFlvdSdyZSBkb2luZyBhbGwgdGhpcyB0byB0cnkgYW5kIG1ha2UgJyptZW0gPScgdGhlIGZpcnN0 IHdyaXRlIHRvIHRoZQpjYWNoZT8gV2UgY2FuJ3QgZG8gdGhpcyBpbiBDOiB0aGUgY29tcGlsZXIg bWF5IHdyaXRlIHJlZ2lzdGVycyB0byB0aGUgc3RhY2suCkV2ZW4gaWYgaXQgZGlkbid0LCBJIGRv bid0IHRoaW5rIHdlIGNhbiBkbyB0aGlzIGF0IGFsbCBhcyB3ZSBtYXkgdGFrZSBhCmZpcm13YXJl LWludGVycnVwdCwgb3IgYSByZWFsLWludGVycnVwdCB0byBhIGh5cGVydmlzb3IgaGVyZS4KCldo YXQgaGFwcGVucyBpZiBhIENQVSAobm90IG5lY2Vzc2FyaWx5IHRoaXMgb25lKSBkZWNpZGVzIHRv IHJlYWQgKm1lbT8KCgo+ICsJX19mbHVzaF9kY2FjaGVfYXJlYShtZW0sIDgpOwo+ICsJdmFsICY9 IH5MMV9FUlJfSU5KX0VOOwo+ICsJYXNtIHZvbGF0aWxlKCJkc2Igc3kiKTsKPiArCWFzbSB2b2xh dGlsZSgibXNyIFMzXzFfQzE1X0MyXzAsICUwIiA6OiAiciIgKHZhbCkpOwo+ICsJYXNtIHZvbGF0 aWxlKCJpc2Igc3kiKTsKPiArCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmNvcnRleF9lZGFjX2xv Y2ssIGZsYWdzKTsKPiArfQo+ICsKPiArc3RhdGljIGlubGluZSB2b2lkIHJlYWRfbDJhY3Rscih2 b2lkICppbmZvKQo+ICt7Cj4gKwl1NjQgdmFsOwo+ICsJaW50IGNwdSA9IHNtcF9wcm9jZXNzb3Jf aWQoKTsKPiArCj4gKwlhc20gdm9sYXRpbGUoIm1ycyAlMCwgUzNfMV9DMTVfQzBfMCIgOiAiPXIi ICh2YWwpKTsKCj4gKwlwZXJfY3B1KGwyYWN0bHIsIGNwdSkgPSB2YWw7Cj4gK30KPiArCj4gK3N0 YXRpYyBpbmxpbmUgdm9pZCB3cml0ZV9sMmFjdGxyKGludCAqbWVtKQo+ICt7Cj4gKwl1NjQgdmFs Owo+ICsJdW5zaWduZWQgbG9uZyBmbGFnczsKPiArCj4gKwlzcGluX2xvY2tfaXJxc2F2ZSgmY29y dGV4X2VkYWNfbG9jaywgZmxhZ3MpOwo+ICsJX19mbHVzaF9kY2FjaGVfYXJlYShtZW0sIDgpOwo+ ICsJX19mbHVzaF9sMV9kY2FjaGVfd2F5KHZpcnRfdG9fcGh5cyhtZW0pKTsKPiArCWFzbSB2b2xh dGlsZSgibXJzICUwLCBTM18xX0MxNV9DMF8wIiA6ICI9ciIgKHZhbCkpOwo+ICsJdmFsIHw9IEwy RF9FUlJfSU5KX0VOOwo+ICsJYXNtIHZvbGF0aWxlKCJkc2Igc3kiKTsKPiArCWFzbSB2b2xhdGls ZSgibXNyIFMzXzFfQzE1X0MwXzAsICUwIiA6OiAiciIgKHZhbCkpOwo+ICsJYXNtIHZvbGF0aWxl KCJpc2Igc3kiKTsKPiArCS8qIG1ha2UgY2FjaGUgZGlydHkgKi8KPiArCSptZW0gPSAweERFQURC RUVGOwkvKiBFcnJvciB3aWxsIGJlIHJlcG9ydGVkIHdoZW4gTDIgaXMgYWNjZXNzZWQuICovCgpB cyBhYm92ZSBJIGRvbid0IHRoaW5rIHdlIGNhbiBkbyB0aGlzLiBXaGF0IGhhcHBlbnMgaWYgYW5v dGhlciBDUFUgYWNjZXNzZXMgTDI/CgoKPiArCV9fZmx1c2hfbDFfZGNhY2hlX3dheSh2aXJ0X3Rv X3BoeXMobWVtKSk7Cj4gKwlfX2ZsdXNoX2RjYWNoZV9hcmVhKG1lbSwgOCk7Cj4gKwl2YWwgJj0g fkwyRF9FUlJfSU5KX0VOOwo+ICsJYXNtIHZvbGF0aWxlKCJkc2Igc3kiKTsKPiArCWFzbSB2b2xh dGlsZSgibXNyIFMzXzFfQzE1X0MwXzAsICUwIiA6OiAiciIgKHZhbCkpOwo+ICsJYXNtIHZvbGF0 aWxlKCJpc2Igc3kiKTsKPiArCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJmNvcnRleF9lZGFjX2xv Y2ssIGZsYWdzKTsKPiArfQo+ICsKPiArc3RhdGljIGlubGluZSB2b2lkIHdyaXRlX2wyZWN0bHJf ZWwxKHZvaWQgKmluZm8pCj4gK3sKPiArCXU2NCB2YWw7Cj4gKwlpbnQgY3B1ID0gc21wX3Byb2Nl c3Nvcl9pZCgpOwo+ICsKPiArCWFzbSB2b2xhdGlsZSgibXJzICUwLCBTM18xX0MxMV9DMF8zIiA6 ICI9ciIgKHZhbCkpOwo+ICsJaWYgKHZhbCAmIEwyX0VSUl9JTlQpIHsKPiArCQlwcl9kZWJ1Zygi bDJlY3Rscl9lbDEgb24gY3B1ICVkIHJlYWRzIDB4JWxseFxuIiwgY3B1LCB2YWwpOwo+ICsJCXZh bCAmPSB+TDJfRVJSX0lOVDsKPiArCQlhc20gdm9sYXRpbGUoIm1zciBTM18xX0MxMV9DMF8zLCAl MCIgOjogInIiICh2YWwpKTsKPiArCX0KPiArfQoKSXNuJ3QgdGhpcyBtb3JlIGxpa2UgYSByZXNl dCBMMl9FUlJfSU5UIGJpdCB0aGFuICd3cml0ZV9sMmVjdGxyX2VsMSgpOz8KCgo+ICsKPiArc3Rh dGljIGlubGluZSB2b2lkIHdyaXRlX2NwdW1lcnJzcl9lbDEodTY0IHZhbCkKPiArewo+ICsJYXNt IHZvbGF0aWxlKCJtc3IgczNfMV9jMTVfYzJfMiwgJTAiIDo6ICJyIiAodmFsKSk7Cj4gK30KPiAr Cj4gK3N0YXRpYyB2b2lkIGE1M19hbGxvd19sMWwyX2Vycl9pbmoodm9pZCAqaW5mbykKPiArewo+ ICsJaW50IGNwdSA9IHNtcF9wcm9jZXNzb3JfaWQoKTsKPiArCXN0cnVjdCBhcm1fc21jY2NfcmVz IHJlczsKPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwo+ICsJcHJfZGVidWcoIiVzOiBjcHUg aXMgJWRcbiIsIF9fZnVuY19fLCBjcHUpOwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJmNvcnRleF9l ZGFjX2xvY2ssIGZsYWdzKTsKCj4gKwlhcm1fc21jY2Nfc21jKFNJUF9BTExPV19MMUwyX0VSUl8z MiwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgJnJlcyk7CgpXaGVyZSBpcyB0aGlzIGNhbGwgZGVmaW5l ZD8gKEl0cyBzdGFuZGFyZGlzZWQgc29tZXdoZXJlIHJpZ2h0PykKSG93IGRvIHdlIGtub3cgZmly bXdhcmUgaW1wbGVtZW50cyBpdD8KSG93IGRvIHdlIGtub3cgJ1NNQycgaXMgdGhlIFNNQ0NDIGNv bmR1aXQgdG8gdXNlPyBUaGlzIHdpbGwgdW5kZWYgaWYgaXRzIHJ1biBpbgphIHZpcnR1YWwgbWFj aGluZS4uLgoKCj4gKwlwZXJfY3B1KGFjdGxyX2VuLCBjcHUpID0gcmVzLmEwOwo+ICsJc3Bpbl91 bmxvY2tfaXJxcmVzdG9yZSgmY29ydGV4X2VkYWNfbG9jaywgZmxhZ3MpOwo+ICsJcHJfZGVidWco IiVzOiByZXR1cm4gaXMgJWxkXG4iLCBfX2Z1bmNfXywgcmVzLmEwKTsKPiArfQo+ICsKPiArc3Rh dGljIHZvaWQgYTUzX2FsbG93X2wxbDJfZXJyX2lycV9jbHIodm9pZCAqaW5mbykKPiArewo+ICsJ aW50IGNwdSA9IHNtcF9wcm9jZXNzb3JfaWQoKTsKPiArCXN0cnVjdCBhcm1fc21jY2NfcmVzIHJl czsKPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gKwo+ICsJcHJfZGVidWcoIiVzOiBjcHUgaXMg JWRcbiIsIF9fZnVuY19fLCBjcHUpOwo+ICsJc3Bpbl9sb2NrX2lycXNhdmUoJmNvcnRleF9lZGFj X2xvY2ssIGZsYWdzKTsKPiArCWFybV9zbWNjY19zbWMoU0lQX0FMTE9XX0wyX0NMUl8zMiwgMCwg MCwgMCwgMCwgMCwgMCwgMCwgJnJlcyk7Cj4gKwlwZXJfY3B1KGwyZWN0bHJfZW4sIGNwdSkgPSBy ZXMuYTA7Cj4gKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZjb3J0ZXhfZWRhY19sb2NrLCBmbGFn cyk7Cj4gKwlwcl9kZWJ1ZygiJXM6IHJldHVybiBpcyAlbGRcbiIsIF9fZnVuY19fLCByZXMuYTAp Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW5saW5lIHZvaWQgcmVhZF9jcHVtZXJyc3JfZWwxKHZvaWQg KmluZm8pCj4gK3sKPiArCXU2NCB2YWw7Cj4gKwlpbnQgY3B1ID0gc21wX3Byb2Nlc3Nvcl9pZCgp Owo+ICsKPiArCWFzbSB2b2xhdGlsZSgibXJzICUwLCBzM18xX2MxNV9jMl8yIiA6ICI9ciIgKHZh bCkpOwo+ICsJcGVyX2NwdShjcHVtZXJyLCBjcHUpID0gdmFsOwo+ICsJaWYgKHZhbCAmIH5DUFVN RVJSU1JfUkFNSURfTUFTSykgewkvKiBTa2lwIFJBTUlEICovCj4gKwkJcHJfZGVidWcoImNwdSAl ZCByZWFkcyBjcHVtZXJyc3JfZWwxIDB4JWxseFxuIiwgY3B1LCB2YWwpOwo+ICsJCS8qIGNsZWFy IHRoZSByZWdpc3RlciBzaW5jZSB3ZSBhbHJlYWR5IHN0b3JlZCBpdCAqLwo+ICsJCXdyaXRlX2Nw dW1lcnJzcl9lbDEoMCk7Cj4gKwl9IGVsc2UgaWYgKGwxX2NlX3N3X2luamVjdF9jb3VudCA+IDAp IHsKPiArCQlsMV9jZV9zd19pbmplY3RfY291bnQtLTsKPiArCQlwcl9kZWJ1ZygiaW5qZWN0IGNv cnJlY3RhYmxlIGVycm9ycyB0byBjcHUgJWRcbiIsIGNwdSk7Cj4gKwkJcGVyX2NwdShjcHVtZXJy LCBjcHUpID0gKDFVTCA8PCAzMSk7CS8qIHZhbGlkIGJpdCAqLwo+ICsJfSBlbHNlIGlmIChsMV91 ZV9zd19pbmplY3RfY291bnQgPiAwKSB7Cj4gKwkJbDFfdWVfc3dfaW5qZWN0X2NvdW50LS07Cj4g KwkJcHJfZGVidWcoImluamVjdCBVbmNvcnJlY3RhYmxlIGVycm9ycyB0byBjcHUgJWRcbiIsIGNw dSk7Cj4gKwkJcGVyX2NwdShjcHVtZXJyLCBjcHUpID0gKDFVTCA8PCA2MykgfCAoMVVMIDw8IDMx KTsKPiArCX0KPiArfQo+ICsKPiArc3RhdGljIGlubGluZSB2b2lkIHdyaXRlX2wybWVycnNyX2Vs MSh1NjQgdmFsKQo+ICt7Cj4gKwlhc20gdm9sYXRpbGUoIm1zciBzM18xX2MxNV9jMl8zLCAlMCIg OjogInIiICh2YWwpKTsKPiArfQo+ICsKPiArc3RhdGljIGlubGluZSB2b2lkIHJlYWRfbDJtZXJy c3JfZWwxKHZvaWQgKmluZm8pCj4gK3sKPiArCXU2NCB2YWw7Cj4gKwlpbnQgY3B1ID0gc21wX3By b2Nlc3Nvcl9pZCgpOwo+ICsKPiArCWFzbSB2b2xhdGlsZSgibXJzICUwLCBzM18xX2MxNV9jMl8z IiA6ICI9ciIgKHZhbCkpOwo+ICsJcGVyX2NwdShsMm1lcnIsIGNwdSkgPSB2YWw7Cj4gKwlpZiAo dmFsICYgfkwyTUVSUlNSX1JBTUlEX01BU0spIHsJLyogU2tpcCBSQU1JRCAqLwo+ICsJCXByX2Rl YnVnKCJjcHUgJWQgcmVhZHMgbDJtZXJyc3JfZWwxIDB4JWxseFxuIiwgY3B1LCB2YWwpOwo+ICsJ CS8qIGNsZWFyIHRoZSByZWdpc3RlciBzaW5jZSB3ZSBhbHJlYWR5IHN0b3JlZCBpdCAqLwo+ICsJ CXdyaXRlX2wybWVycnNyX2VsMSgwKTsKPiArCX0gZWxzZSBpZiAobDJfY2Vfc3dfaW5qZWN0X2Nv dW50ID4gMCkgewo+ICsJCWwyX2NlX3N3X2luamVjdF9jb3VudC0tOwo+ICsJCXByX2RlYnVnKCJp bmplY3QgY29ycmVjdGFibGUgZXJyb3JzIHRvIEwyIG9uIGNwdSAlZFxuIiwgY3B1KTsKCj4gKwkJ cGVyX2NwdShsMm1lcnIsIGNwdSkgPSAoMVVMIDw8IDMxKTsJLyogdmFsaWQgYml0ICovCgpQbGVh c2UgY3JlYXRlIG5hbWVkIG1hY3JvcyBmb3IgdGhlc2UgYml0czoKfCAjZGVmaW5lIEE1M19MMk1F UlJfVkFMSUQJQklUKDMxKQoKPiArCX0gZWxzZSBpZiAobDJfdWVfc3dfaW5qZWN0X2NvdW50ID4g MCkgewo+ICsJCWwyX3VlX3N3X2luamVjdF9jb3VudC0tOwo+ICsJCXByX2RlYnVnKCJpbmplY3Qg VW5jb3JyZWN0YWJsZSBlcnJvcnMgdG8gTDIgb24gY3B1ICVkXG4iLCBjcHUpOwoKPiArCQlwZXJf Y3B1KGwybWVyciwgY3B1KSA9ICgxVUwgPDwgNjMpIHwgKDFVTCA8PCAzMSk7Cgo+ICsJfQo+ICt9 Cj4gK3N0YXRpYyB2b2lkIHJlYWRfZXJyb3JzKHZvaWQgKmluZm8pCj4gK3sKPiArCXJlYWRfY3B1 bWVycnNyX2VsMShpbmZvKTsKPiArCXJlYWRfbDJtZXJyc3JfZWwxKGluZm8pOwo+ICsJd3JpdGVf bDJlY3Rscl9lbDEoaW5mbyk7Cj4gK30KPiArCj4gKwo+ICsvKiBSZXR1cm5zIDAgZm9yIG5vIGVy cm9yCj4gKyAqCSAgLTEgZm9yIHVuY29ycmVjdGFibGUgZXJyb3IocykKPiArICoJICAgMSBmb3Ig Y29ycmVjdGFibGUgZXJyb3IocykKCklzIGJvdGggYSBwb3NzaWJpbGl0eT8KCj4gKyAqLwo+ICtz dGF0aWMgaW50IHBhcnNlX2NwdW1lcnJzcih1bnNpZ25lZCBpbnQgY3B1KQo+ICt7Cj4gKwl1NjQg dmFsID0gcGVyX2NwdShjcHVtZXJyLCBjcHUpOwo+ICsKPiArCS8qIGNoZWNrIGlmIHdlIGhhdmUg dmFsaWQgZXJyb3IgYmVmb3JlIGNvbnRpbnVpbmcgKi8KPiArCWlmICghQ1BVTUVSUlNSX0VMMV9W QUxJRCh2YWwpKQo+ICsJCXJldHVybiAwOwo+ICsKPiArCWNvcnRleF9wcmludGsoS0VSTl9JTkZP LCAiQ1BVICVkICIsIGNwdSk7Cj4gKwo+ICsJc3dpdGNoIChDUFVNRVJSU1JfRUwxX1JBTUlEKHZh bCkpIHsKPiArCWNhc2UgTDFfSV9UQUdfUkFNOgo+ICsJCXByX2NvbnQoIkwxLUkgVGFnIFJBTSIp Owo+ICsJCWJyZWFrOwo+ICsJY2FzZSBMMV9JX0RBVEFfUkFNOgo+ICsJCXByX2NvbnQoIkwxLUkg RGF0YSBSQU0iKTsKPiArCQlicmVhazsKPiArCWNhc2UgTDFfRF9UQUdfUkFNOgo+ICsJCXByX2Nv bnQoIkwxLUQgVGFnIFJBTSIpOwo+ICsJCWJyZWFrOwo+ICsJY2FzZSBMMV9EX0RBVEFfUkFNOgo+ ICsJCXByX2NvbnQoIkwxLUQgRGF0YSBSQU0iKTsKPiArCQlicmVhazsKPiArCWNhc2UgTDFfRF9E SVJUWV9SQU06Cj4gKwkJcHJfY29udCgiTDEgRGlydHkgUkFNIik7Cj4gKwkJYnJlYWs7Cj4gKwlj YXNlIFRMQl9SQU06Cj4gKwkJcHJfY29udCgiVExCIFJBTSIpOwo+ICsJCWJyZWFrOwo+ICsJZGVm YXVsdDoKPiArCQlwcl9jb250KCJ1bmtub3duIik7Cj4gKwkJYnJlYWs7Cj4gKwl9Cj4gKwlwcl9j b250KCIgZXJyb3IocykgZGV0ZWN0ZWRcbiIpOwo+ICsKPiArCWlmIChDUFVNRVJSU1JfRUwxX0ZB VEFMKHZhbCkpIHsKPiArCQljb3J0ZXhfcHJpbnRrKEtFUk5fSU5GTywKPiArCQkJICAgICAgIkNQ VSAlZCBMMSBmYXRhbCBlcnJvcihzKSBkZXRlY3RlZCAoMHglbGx4KVxuIiwKPiArCQkJICAgICAg Y3B1LCB2YWwpOwo+ICsJCXJldHVybiAtMTsKPiArCX0KPiArCj4gKwlyZXR1cm4gMTsKPiArfQo+ ICsKPiArc3RhdGljIGludCBwYXJzZV9sMm1lcnJzcih1bnNpZ25lZCBpbnQgY3B1KQo+ICt7Cj4g Kwl1NjQgdmFsID0gcGVyX2NwdShsMm1lcnIsIGNwdSk7Cj4gKwo+ICsJLyogY2hlY2sgaWYgd2Ug aGF2ZSB2YWxpZCBlcnJvciBiZWZvcmUgY29udGludWluZyAqLwo+ICsJaWYgKCFMMk1FUlJTUl9F TDFfVkFMSUQodmFsKSkKPiArCQlyZXR1cm4gMDsKPiArCj4gKwljb3J0ZXhfcHJpbnRrKEtFUk5f SU5GTywgIkNQVSAlZCBMMiAlcyBlcnJvcihzKSBkZXRlY3RlZCAoMHglbGx4KVxuIiwKPiArCQkg ICAgICBjcHUsIEwyTUVSUlNSX0VMMV9GQVRBTCh2YWwpID8gImZhdGFsIiA6ICIiLCB2YWwpOwo+ ICsKPiArCXJldHVybiBMMk1FUlJTUl9FTDFfRkFUQUwodmFsKSA/IC0xIDogMTsKPiArfQo+ICsK PiArI2RlZmluZSBNRVNTQUdFX1NJWkUgNDAKPiArc3RhdGljIHZvaWQgY29ydGV4X2FybTY0X2Vk YWNfY2hlY2soc3RydWN0IGVkYWNfZGV2aWNlX2N0bF9pbmZvICplZGFjX2N0bCkKPiArewo+ICsJ aW50IGNwdTsKPiArCWNoYXIgbXNnW01FU1NBR0VfU0laRV07Cj4gKwljYWxsX3NpbmdsZV9kYXRh X3QgKmNzZDsKPiArCj4gKwlnZXRfb25saW5lX2NwdXMoKTsKPiArCWZvcl9lYWNoX2NwdV9hbmQo Y3B1LCBjcHVfb25saW5lX21hc2ssICZjb21wYXRfbWFzaykgewo+ICsJCWNzZCA9ICZwZXJfY3B1 KGNzZF9jaGVjaywgY3B1KTsKPiArCQljc2QtPmZ1bmMgPSByZWFkX2Vycm9yczsKPiArCQljc2Qt PmluZm8gPSBOVUxMOwo+ICsJCWNzZC0+ZmxhZ3MgPSAwOwo+ICsJCS8qIFJlYWQgQ1BVIEwxIGVy cm9yICovCj4gKwkJc21wX2NhbGxfZnVuY3Rpb25fc2luZ2xlX2FzeW5jKGNwdSwgY3NkKTsKCj4g KwkJLyogV2FpdCB1bnRpbCBmbGFncyBjbGVhcmVkICovCj4gKwkJc21wX2NvbmRfbG9hZF9hY3F1 aXJlKCZjc2QtPmZsYWdzLCAhVkFMKTsKClNvIHRoaXMgQ1BVIHdhaXRzIGluIElSUSBjb250ZXh0 IGZvciBlYWNoIENQVSBpbiBjb21wYXRfbWFzayB0byBkbyB0aGUgd29yay4KV2hhdCBoYXBwZW5z IGlmIGFub3RoZXIgZHJpdmVyIGRvZXMgdGhlIHNhbWU/IFdvbid0IHRoaXMgZGVhZGxvY2s/CgpJ IHRoaW5rIHRoZSB3aG9sZSBwb2ludCBvZiB0aGlzIHNtcF9jYWxsX2Z1bmN0aW9uX3NpbmdsZV9h c3luYygpIGNhbGwgaXMgeW91CmRvbid0IHdhaXQgaW4gSVJRIGNvbnRleHQgZm9yIGl0IHRvIGZp bmlzaC4KCgpUaGUgcHJvYmxlbSBoZXJlIGlzIHRoZSBJUlEgaXNuJ3QgYSBwZXItY3B1IFBQSSwg YnV0IHRoZSByZWdpc3RlciBmb3IKYWNrbm93bGVkZ2luZyB0aGUgaW50ZXJydXB0IGlzIGEgcGVy LWNwdSBzeXN0ZW0gcmVnaXN0ZXIuIENhbiB3ZSBhc2sgdGhlIGlycWNoaXAKdG8gZGlzYWJsZSB0 aGUgSVJRIHVudGlsIHdlJ3ZlIGRvbmUgdGhlIHBlci1jcHUgd29yayB0byBjbGVhciBpdD8KCgoK PiArCX0KPiArCXB1dF9vbmxpbmVfY3B1cygpOwo+ICsKPiArCWNwdW1hc2tfY2xlYXIoJmwxX2Nl X2NwdV9tYXNrKTsKPiArCWNwdW1hc2tfY2xlYXIoJmwxX3VlX2NwdV9tYXNrKTsKPiArCWNwdW1h c2tfY2xlYXIoJmwyX2NlX2NwdV9tYXNrKTsKPiArCWNwdW1hc2tfY2xlYXIoJmwyX3VlX2NwdV9t YXNrKTsKPiArCWZvcl9lYWNoX2NwdV9hbmQoY3B1LCBjcHVfb25saW5lX21hc2ssICZjb21wYXRf bWFzaykgewo+ICsJCXN3aXRjaCAocGFyc2VfY3B1bWVycnNyKGNwdSkpIHsKPiArCQkJY2FzZSAt MToKPiArCQkJCS8qIGZhdGFsIGVycm9yICovCj4gKwkJCQljcHVtYXNrX3NldF9jcHUoY3B1LCAm bDFfdWVfY3B1X21hc2spOwo+ICsJCQkJYnJlYWs7Cj4gKwkJCWNhc2UgMToKPiArCQkJCS8qIGNv cnJlY3RhYmxlIGVycm9yKHMpICovCj4gKwkJCQljcHVtYXNrX3NldF9jcHUoY3B1LCAmbDFfY2Vf Y3B1X21hc2spOwo+ICsJCQkJYnJlYWs7Cj4gKwkJCWNhc2UgMDoKPiArCQkJCS8qIGZhbGwgdGhy b3VnaCAqLwo+ICsJCQlkZWZhdWx0Ogo+ICsJCQkJYnJlYWs7Cj4gKwkJfQo+ICsJCXN3aXRjaCAo cGFyc2VfbDJtZXJyc3IoY3B1KSkgewo+ICsJCQljYXNlIC0xOgo+ICsJCQkJLyogZmF0YWwgZXJy b3IgKi8KPiArCQkJCWNwdW1hc2tfc2V0X2NwdShjcHUsICZsMl91ZV9jcHVfbWFzayk7Cj4gKwkJ CQlicmVhazsKPiArCQkJY2FzZSAxOgo+ICsJCQkJLyogY29ycmVjdGFibGUgZXJyb3IocykgKi8K PiArCQkJCWNwdW1hc2tfc2V0X2NwdShjcHUsICZsMl9jZV9jcHVfbWFzayk7Cj4gKwkJCQlicmVh azsKPiArCQkJY2FzZSAwOgo+ICsJCQkJLyogZmFsbCB0aHJvdWdoICovCj4gKwkJCWRlZmF1bHQ6 Cj4gKwkJCQlicmVhazsKPiArCQl9Cj4gKwl9Cj4gKwo+ICsJZm9yX2VhY2hfY3B1KGNwdSwgJmwx X3VlX2NwdV9tYXNrKSB7Cj4gKwkJc25wcmludGYobXNnLCBNRVNTQUdFX1NJWkUsICJGYXRhbCBl cnJvcihzKSBvbiBDUFUgJWRcbiIsIGNwdSk7Cj4gKwkJZWRhY19kZXZpY2VfaGFuZGxlX3VlKGVk YWNfY3RsLCAwLCAwLCBtc2cpOwo+ICsJfQo+ICsKPiArCWZvcl9lYWNoX2NwdShjcHUsICZsMV9j ZV9jcHVfbWFzaykgewo+ICsJCXNucHJpbnRmKG1zZywgTUVTU0FHRV9TSVpFLCAiQ29ycmVjdGFi bGUgZXJyb3Iocykgb24gQ1BVICVkXG4iLCBjcHUpOwo+ICsJCWVkYWNfZGV2aWNlX2hhbmRsZV9j ZShlZGFjX2N0bCwgMCwgMCwgbXNnKTsKPiArCX0KPiArCj4gKwlmb3JfZWFjaF9jcHUoY3B1LCAm bDJfdWVfY3B1X21hc2spIHsKPiArCQlzbnByaW50Zihtc2csIE1FU1NBR0VfU0laRSwgIkZhdGFs IGVycm9yKHMpIG9uIENQVSAlZFxuIiwgY3B1KTsKPiArCQllZGFjX2RldmljZV9oYW5kbGVfdWUo ZWRhY19jdGwsIDAsIDEsIG1zZyk7Cj4gKwl9Cj4gKwo+ICsJZm9yX2VhY2hfY3B1KGNwdSwgJmwy X2NlX2NwdV9tYXNrKSB7Cj4gKwkJc25wcmludGYobXNnLCBNRVNTQUdFX1NJWkUsICJDb3JyZWN0 YWJsZSBlcnJvcihzKSBvbiBDUFUgJWRcbiIsIGNwdSk7Cj4gKwkJZWRhY19kZXZpY2VfaGFuZGxl X2NlKGVkYWNfY3RsLCAwLCAxLCBtc2cpOwo+ICsJfQo+ICsKPiArCWlmICghY3B1bWFza19lbXB0 eSgmbDFfY2VfY3B1X21hc2spIHx8Cj4gKwkgICAgIWNwdW1hc2tfZW1wdHkoJmwyX2NlX2NwdV9t YXNrKSB8fAo+ICsJICAgICFjcHVtYXNrX2VtcHR5KCZsMV91ZV9jcHVfbWFzaykgfHwKPiArCSAg ICAhY3B1bWFza19lbXB0eSgmbDJfdWVfY3B1X21hc2spKSB7Cj4gKwkJaWYgKHBvbGxfbXNlYyA+ IE1JTl9QT0xMX01TRUMpIHsKPiArCQkJcG9sbF9tc2VjID4+PSAxOwo+ICsJCQllZGFjX2Rldmlj ZV9yZXNldF9kZWxheV9wZXJpb2QoZWRhY19jdGwsIHBvbGxfbXNlYyk7Cj4gKwkJfSBlbHNlIHsK PiArCQkJY29ydGV4X3ByaW50ayhLRVJOX0NSSVQsCj4gKwkJCQkgICAgICAiRXhjZXNzaXZlIGNv cnJlY3RhYmxlIGVycm9yc1xuIik7Cj4gKwkJfQo+ICsJfSBlbHNlIHsKPiArCQlpZiAocG9sbF9t c2VjIDwgTUFYX1BPTExfTVNFQykgewo+ICsJCQlwb2xsX21zZWMgPDw9IDE7Cj4gKwkJCWVkYWNf ZGV2aWNlX3Jlc2V0X2RlbGF5X3BlcmlvZChlZGFjX2N0bCwgcG9sbF9tc2VjKTsKPiArCQl9Cj4g Kwl9Cj4gK30KClsuLi5dCgo+ICtzdGF0aWMgaXJxcmV0dXJuX3QgY29ydGV4X2VkYWNfaXNyKGlu dCBpcnEsIHZvaWQgKmRldl9pZCkKPiArewo+ICsJc3RydWN0IGVkYWNfZGV2aWNlX2N0bF9pbmZv ICplZGFjX2N0bCA9IGRldl9pZDsKPiArCj4gKwlwcl9kZWJ1ZygiR290IElSUVxuIik7Cj4gKwlj b3J0ZXhfYXJtNjRfZWRhY19jaGVjayhlZGFjX2N0bCk7Cj4gKwo+ICsJcmV0dXJuIElSUV9IQU5E TEVEOwo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNvcnRleF9hcm02NF9lZGFjX3Byb2JlKHN0cnVj dCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCj4gK3sKPiArCWludCBpLCByYywgY3B1LCBudW1fYXR0 cjsKPiArCXN0cnVjdCBlZGFjX2RldmljZV9jdGxfaW5mbyAqZWRhY19jdGw7Cj4gKwlzdHJ1Y3Qg ZGV2aWNlICpkZXYgPSAmcGRldi0+ZGV2Owo+ICsJc3RydWN0IGNvcnRleF9wZGF0YSAqcGRhdGE7 Cj4gKwlzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wLCAqZG4gPSBwZGV2LT5kZXYub2Zfbm9kZTsKPiAr CXN0cnVjdCBvZl9waGFuZGxlX2l0ZXJhdG9yIGl0Owo+ICsJc3RydWN0IGVkYWNfZGV2X3N5c2Zz X2F0dHJpYnV0ZSAqYXR0cjsKPiArCWNvbnN0IF9fYmUzMiAqY2VsbDsKPiArCXU2NCBtcGlkcjsK PiArCj4gKwljcHVtYXNrX2NsZWFyKCZjb21wYXRfbWFzayk7Cj4gKwlvZl9mb3JfZWFjaF9waGFu ZGxlKCZpdCwgcmMsIGRuLCAiY3B1cyIsIE5VTEwsIDApIHsKPiArCQlucCA9IGl0Lm5vZGU7Cj4g KwkJY2VsbCA9IG9mX2dldF9wcm9wZXJ0eShucCwgInJlZyIsIE5VTEwpOwo+ICsJCWlmICghY2Vs bCkgewo+ICsJCQlwcl9lcnIoIiVwT0Y6IG1pc3NpbmcgcmVnIHByb3BlcnR5XG4iLCBucCk7Cj4g KwkJCWNvbnRpbnVlOwo+ICsJCX0KPiArCQltcGlkciA9IG9mX3JlYWRfbnVtYmVyKGNlbGwsIG9m X25fYWRkcl9jZWxscyhucCkpOwo+ICsJCWNwdSA9IGdldF9sb2dpY2FsX2luZGV4KG1waWRyKTsK PiArCQlpZiAoY3B1IDwgMCkgewo+ICsJCQlwcl9lcnIoIkJhZCBDUFUgbnVtYmVyIGZvciBtcGlk ciAweCVsbHgiLCBtcGlkcik7Cj4gKwkJCWNvbnRpbnVlOwo+ICsJCX0KPiArCQljcHVtYXNrX3Nl dF9jcHUoY3B1LCAmY29tcGF0X21hc2spOwo+ICsJfQo+ICsKPiArCXByX2RlYnVnKCJjb21wYXRf bWFzayBpcyAlKnBibFxuIiwgY3B1bWFza19wcl9hcmdzKCZjb21wYXRfbWFzaykpOwo+ICsKPiAr CWlmIChvZl9kZXZpY2VfaXNfY29tcGF0aWJsZShkbiwgImFybSxjb3J0ZXgtYTUzLWVkYWMiKSkg ewo+ICsJCW51bV9hdHRyID0gQVJSQVlfU0laRShkZXZpY2Vfc3lzZnNfYXR0cik7Cj4gKwkJZ2V0 X29ubGluZV9jcHVzKCk7Cj4gKwkJZm9yX2VhY2hfY3B1X2FuZChjcHUsIGNwdV9vbmxpbmVfbWFz aywgJmNvbXBhdF9tYXNrKSB7Cj4gKwkJCXNtcF9jYWxsX2Z1bmN0aW9uX3NpbmdsZShjcHUsIGE1 M19hbGxvd19sMWwyX2Vycl9pbmosIE5VTEwsIDEpOwo+ICsJCQlpZiAocGVyX2NwdShhY3Rscl9l biwgY3B1KSkgewo+ICsJCQkJcHJfZXJyKCJGYWlsZWQgdG8gZW5hYmxlIGhhcmR3YXJlIGVycm9y IGluamVjdGlvbiAoJWxkKVxuIiwKPiArCQkJCSAgICAgICBwZXJfY3B1KGFjdGxyX2VuLCBjcHUp KTsKPiArCQkJCW51bV9hdHRyIC09IDI7Cj4gKwkJCQlicmVhazsKPiArCQkJfQo+ICsJCX0KPiAr CQlwdXRfb25saW5lX2NwdXMoKTsKPiArCX0gZWxzZSB7Cj4gKwkJbnVtX2F0dHIgPSBBUlJBWV9T SVpFKGRldmljZV9zeXNmc19hdHRyKSAtIDI7Cj4gKwl9Cj4gKwo+ICsJLyogUE9MTCBtb2RlIGlz IHVzZWQgdG8gZGV0ZWN0IGNvcnJlY3RhYmxlIGVycm9ycyAqLwo+ICsJZWRhY19vcF9zdGF0ZSA9 IEVEQUNfT1BTVEFURV9QT0xMOwo+ICsKPiArCWVkYWNfY3RsID0gZWRhY19kZXZpY2VfYWxsb2Nf Y3RsX2luZm8oc2l6ZW9mKCpwZGF0YSksICJjcHVfY2FjaGUiLAo+ICsJCQkJCSAgICAgIDEsICJM IiwgMiwgMSwgTlVMTCwgMCwKPiArCQkJCQkgICAgICBlZGFjX2RldmljZV9hbGxvY19pbmRleCgp KTsKPiArCWlmIChJU19FUlIoZWRhY19jdGwpKQo+ICsJCXJldHVybiAtRU5PTUVNOwo+ICsKPiAr CXBkYXRhID0gZWRhY19jdGwtPnB2dF9pbmZvOwo+ICsJYXR0ciA9IGRldm1fa3phbGxvYyhkZXYs Cj4gKwkJCSAgICBzaXplb2Yoc3RydWN0IGVkYWNfZGV2X3N5c2ZzX2F0dHJpYnV0ZSkgKiBudW1f YXR0ciwKPiArCQkJICAgIEdGUF9LRVJORUwpOwo+ICsJaWYgKCFhdHRyKSB7Cj4gKwkJcmMgPSAt RU5PTUVNOwo+ICsJCWdvdG8gb3V0X2RldjsKPiArCX0KPiArCj4gKwlmb3IgKGkgPSAwOyBpIDwg bnVtX2F0dHIgLSAxOyBpKyspIHsKPiArCQlhdHRyW2ldLmF0dHIubmFtZSA9IGRldmljZV9zeXNm c19hdHRyW2ldLmF0dHIubmFtZTsKPiArCQlhdHRyW2ldLmF0dHIubW9kZSA9IGRldmljZV9zeXNm c19hdHRyW2ldLmF0dHIubW9kZTsKPiArCQlhdHRyW2ldLnNob3cgPSBkZXZpY2Vfc3lzZnNfYXR0 cltpXS5zaG93Owo+ICsJCWF0dHJbaV0uc3RvcmUgPSBkZXZpY2Vfc3lzZnNfYXR0cltpXS5zdG9y ZTsKPiArCX0KPiArCWVkYWNfY3RsLT5zeXNmc19hdHRyaWJ1dGVzID0gYXR0cjsKPiArCj4gKwly YyA9IG9mX2NvdW50X3BoYW5kbGVfd2l0aF9hcmdzKGRuLCAiY3B1cyIsIE5VTEwpOwo+ICsJaWYg KHJjIDw9IDApIHsKPiArCQlwcl9lcnIoIkludmFsaWQgbnVtYmVyIG9mIHBoYW5kbGVzIGluICdj cHVzJ1xuIik7Cj4gKwkJcmMgPSAtRUlOVkFMOwo+ICsJCWdvdG8gb3V0X2RldjsKPiArCX0KPiAr CXBkYXRhLT5pcnEgPSBwbGF0Zm9ybV9nZXRfaXJxKHBkZXYsIDApOwo+ICsJcHJfZGVidWcoImly cSBpcyAlZFxuIiwgcGRhdGEtPmlycSk7Cj4gKwo+ICsJZWRhY19jdGwtPnBvbGxfbXNlYyA9IHBv bGxfbXNlYzsKPiArCWVkYWNfY3RsLT5lZGFjX2NoZWNrID0gY29ydGV4X2FybTY0X2VkYWNfY2hl Y2s7Cj4gKwllZGFjX2N0bC0+ZGV2ID0gZGV2Owo+ICsJZWRhY19jdGwtPm1vZF9uYW1lID0gZGV2 X25hbWUoZGV2KTsKPiArCWVkYWNfY3RsLT5kZXZfbmFtZSA9IGRldl9uYW1lKGRldik7Cj4gKwll ZGFjX2N0bC0+Y3RsX25hbWUgPSBFREFDX01PRF9TVFI7Cj4gKwlkZXZfc2V0X2RydmRhdGEoZGV2 LCBlZGFjX2N0bCk7Cj4gKwo+ICsJcmMgPSBlZGFjX2RldmljZV9hZGRfZGV2aWNlKGVkYWNfY3Rs KTsKPiArCWlmIChyYykKPiArCQlnb3RvIG91dF9kZXY7Cj4gKwo+ICsJcGRhdGEtPm1lbSA9IGRl dm1fa3phbGxvYyhkZXYsIFBBR0VfU0laRSwgR0ZQX0tFUk5FTCk7Cj4gKwlpZiAoIXBkYXRhLT5t ZW0pCj4gKwkJZ290byBvdXRfbWVtOwo+ICsKPiArCWlmIChwZGF0YS0+aXJxKSB7Cj4gKwkJZ2V0 X29ubGluZV9jcHVzKCk7Cj4gKwkJZm9yX2VhY2hfY3B1X2FuZChjcHUsIGNwdV9vbmxpbmVfbWFz aywgJmNvbXBhdF9tYXNrKSB7Cj4gKwkJCXNtcF9jYWxsX2Z1bmN0aW9uX3NpbmdsZShjcHUsCj4g KwkJCQkJCSBhNTNfYWxsb3dfbDFsMl9lcnJfaXJxX2NsciwKPiArCQkJCQkJIE5VTEwsCj4gKwkJ CQkJCSAxKTsKCkhvdyBkbyB5b3Uga25vdyB0aGlzIGlzIG9ubHkgY2FsbGVkIG9uIHRoZSBBNTNz PyBZb3UgYWRkZWQgYWxsIHRoZSBDUFVzIHRvCmNvbXBhdF9tYXNrLgoKSXQgbWF5IGJlIHdvcnRo IGhhdmluZyBzZXBhcmF0ZSBwcm9iZSBjYWxscyBmb3IgQTUzIGFuZCBBNTcuCgoKVGhhbmtzLAoK SmFtZXMKCgo+ICsJCQlpZiAocGVyX2NwdShsMmVjdGxyX2VuLCBjcHUpKSB7Cj4gKwkJCQlwcl9l cnIoIkZhaWxlZCB0byBlbmFibGUgaW50ZXJydXB0IGNsZWFyaW5nICglbGQpXG4iLAo+ICsJCQkJ ICAgICAgIHBlcl9jcHUobDJlY3Rscl9lbiwgY3B1KSk7Cj4gKwkJCQlyYyA9IC1FQUNDRVM7Cj4g KwkJCQlicmVhazsKPiArCQkJfQo+ICsJCX0KPiArCQlwdXRfb25saW5lX2NwdXMoKTsKPiArCj4g KwkJaWYgKCFyYykgewo+ICsJCQlyYyA9IGRldm1fcmVxdWVzdF9pcnEoZGV2LCBwZGF0YS0+aXJx LCBjb3J0ZXhfZWRhY19pc3IsCj4gKwkJCQkgICAgICAwLCAiY29ydGV4X2VkYWMgZXJyb3IiLCBl ZGFjX2N0bCk7Cj4gKwkJCWlmIChyYyA8IDApIHsKPiArCQkJCXByX2VycigiJXM6IFVuYWJsZSB0 byByZXF1ZXN0IGlycSAlZCBmb3IgY29ydGV4IGVkYWMgZXJyb3JcbiIsCj4gKwkJCQkgICAgICAg X19mdW5jX18sIHBkYXRhLT5pcnEpOwo+ICsJCQkJZ290byBvdXRfaXJxOwo+ICsJCQl9Cj4gKwkJ fQo+ICsJfQo+ICsKPiArCXJldHVybiAwOwo+ICsKPiArb3V0X21lbToKPiArb3V0X2lycToKPiAr CWVkYWNfZGV2aWNlX2RlbF9kZXZpY2UoZWRhY19jdGwtPmRldik7Cj4gKwo+ICtvdXRfZGV2Ogo+ ICsJZWRhY19kZXZpY2VfZnJlZV9jdGxfaW5mbyhlZGFjX2N0bCk7Cj4gKwo+ICsJcmV0dXJuIHJj Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IGNvcnRleF9hcm02NF9lZGFjX3JlbW92ZShzdHJ1Y3Qg cGxhdGZvcm1fZGV2aWNlICpwZGV2KQo+ICt7Cj4gKwlzdHJ1Y3QgZWRhY19kZXZpY2VfY3RsX2lu Zm8gKmVkYWNfY3RsID0gZGV2X2dldF9kcnZkYXRhKCZwZGV2LT5kZXYpOwo+ICsKPiArCWVkYWNf ZGV2aWNlX2RlbF9kZXZpY2UoZWRhY19jdGwtPmRldik7Cj4gKwllZGFjX2RldmljZV9mcmVlX2N0 bF9pbmZvKGVkYWNfY3RsKTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RhdGljIGNv bnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgY29ydGV4X2FybTY0X2VkYWNfb2ZfbWF0Y2hbXSA9IHsK PiArCXsgLmNvbXBhdGlibGUgPSAiYXJtLGNvcnRleC1hNTctZWRhYyIgfSwKPiArCXsgLmNvbXBh dGlibGUgPSAiYXJtLGNvcnRleC1hNTMtZWRhYyIgfSwKPiArCXt9Cj4gK307Cj4gK01PRFVMRV9E RVZJQ0VfVEFCTEUob2YsIGNvcnRleF9hcm02NF9lZGFjX29mX21hdGNoKTsKPiArCj4gK3N0YXRp YyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIGNvcnRleF9hcm02NF9lZGFjX2RyaXZlciA9IHsKPiAr CS5wcm9iZSA9IGNvcnRleF9hcm02NF9lZGFjX3Byb2JlLAo+ICsJLnJlbW92ZSA9IGNvcnRleF9h cm02NF9lZGFjX3JlbW92ZSwKPiArCS5kcml2ZXIgPSB7Cj4gKwkJLm5hbWUgPSBFREFDX01PRF9T VFIsCj4gKwkJLm9mX21hdGNoX3RhYmxlID0gY29ydGV4X2FybTY0X2VkYWNfb2ZfbWF0Y2gsCj4g Kwl9LAo+ICt9Owo+ICttb2R1bGVfcGxhdGZvcm1fZHJpdmVyKGNvcnRleF9hcm02NF9lZGFjX2Ry aXZlcik7Cj4gKwo+ICtNT0RVTEVfTElDRU5TRSgiR1BMIik7Cj4gK01PRFVMRV9BVVRIT1IoIllv cmsgU3VuIDx5b3JrLnN1bkBueHAuY29tPiIpOwo+ICtNT0RVTEVfREVTQ1JJUFRJT04oIkNvcnRl eCBBNTcgYW5kIEE1MyBMMSBhbmQgTDIgY2FjaGUgRURBQyBkcml2ZXIiKTsKLS0tClRvIHVuc3Vi c2NyaWJlIGZyb20gdGhpcyBsaXN0OiBzZW5kIHRoZSBsaW5lICJ1bnN1YnNjcmliZSBsaW51eC1l ZGFjIiBpbgp0aGUgYm9keSBvZiBhIG1lc3NhZ2UgdG8gbWFqb3Jkb21vQHZnZXIua2VybmVsLm9y ZwpNb3JlIG1ham9yZG9tbyBpbmZvIGF0ICBodHRwOi8vdmdlci5rZXJuZWwub3JnL21ham9yZG9t by1pbmZvLmh0bWwK From mboxrd@z Thu Jan 1 00:00:00 1970 From: james.morse@arm.com (James Morse) Date: Thu, 15 Mar 2018 13:33:52 +0000 Subject: [PATCH RFC 1/2] drivers/edac: Add L1 and L2 error detection for A53 and A57 In-Reply-To: <1521073067-24348-1-git-send-email-york.sun@nxp.com> References: <1521073067-24348-1-git-send-email-york.sun@nxp.com> Message-ID: <5AAA7640.3010506@arm.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org Hi York, You have a DT binding in here, please CC the devicetree list. You're touching code under arch/arm64, so you need the arm list too. get_maintainer.pl will take your patch and give you the list of which lists and maintainers to CC. (I've added those lists, the full patch is here: https://patchwork.kernel.org/patch/10283783/ ) Some comments below, I haven't looked in to edac or the manuals for A53/A57. On 15/03/18 00:17, York Sun wrote: > Add error detection for A53 and A57 cores. Hardware error injection > is supported on A53. Software error injection is supported on both. > For hardware error injection on A53 to work, proper access to > L2ACTLR_EL1, CPUACTLR_EL1 needs to be granted by EL3 firmware. This > is done by making an SMC call in the driver. Failure to enable access > disables hardware error injection. For error interrupt to work, > another SMC call enables access to L2ECTLR_EL1. Failure to enable > access disables interrupt for error reporting. This is tricky as there are shipped systems out there without these SMC calls. They need to be discovered in some way. We can't even assume firmware has PSCI, it has to be discovered via APCI/DT. I think it will be cleaner for the presence of this device/compatible to indicate that the registers are enabled for the normal-world, instead of having the OS try to call into firmware to enable it. > Signed-off-by: York Sun > --- > .../devicetree/bindings/edac/cortex-arm64-edac.txt | 37 + > arch/arm64/include/asm/cacheflush.h | 1 + > arch/arm64/mm/cache.S | 35 + > drivers/edac/Kconfig | 6 + > drivers/edac/Makefile | 1 + > drivers/edac/cortex_arm64_l1_l2.c | 741 +++++++++++++++++++++ > drivers/edac/cortex_arm64_l1_l2.h | 55 ++ > 7 files changed, 876 insertions(+) > create mode 100644 Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt > create mode 100644 drivers/edac/cortex_arm64_l1_l2.c > create mode 100644 drivers/edac/cortex_arm64_l1_l2.h > > diff --git a/Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt b/Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt > new file mode 100644 > index 0000000..74a1c2f > --- /dev/null > +++ b/Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt > @@ -0,0 +1,37 @@ > +ARM Cortex A57 and A53 L1/L2 cache error reporting > + > +CPU Memory Error Syndrome and L2 Memory Error Syndrome registers can be used > +for checking L1 and L2 memory errors. However, only A53 supports double-bit > +error injection to L1 and L2 memory. This driver uses the hardware error > +injection when available, but also provides a way to inject errors by > +software. Both A53 and A57 supports interrupt when multi-bit errors happen. > +To use hardware error injection and the interrupt, proper access needs to be > +granted in ACTLR_EL3 (and/or ACTLR_EL2) register by EL3 firmware SMC call. How can Linux know whether firmware toggled these bits? How can it know if it needs to make an SMC call to do the work? This looks like platform policy, I'm not sure how this gets described... > +Correctable errors do not trigger such interrupt. This driver uses dynamic > +polling internal to check for errors. The more errors detected, the more > +frequently it polls. Combining with interrupt, this driver can detect > +correctable and uncorrectable errors. However, if the uncorrectable errors > +cause system abort exception, this drivr is not able to report errors in time. > + > +The following section describes the Cortex A57/A53 EDAC DT node binding. > + > +Required properties: > +- compatible: Should be "arm,cortex-a57-edac" or "arm,cortex-a53-edac" > +- cpus: Should be a list of compatible cores > + > +Optional properties: > +- interrupts: Interrupt number if supported > + > +Example: > + edac { > + compatible = "arm,cortex-a53-edac"; > + cpus = <&cpu0>, > + <&cpu1>, > + <&cpu2>, > + <&cpu3>; > + interrupts = <0 108 0x4>; > + > + }; > + > diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h > index 76d1cc8..f1cd090 100644 > --- a/arch/arm64/include/asm/cacheflush.h > +++ b/arch/arm64/include/asm/cacheflush.h > @@ -73,6 +73,7 @@ extern void __clean_dcache_area_pop(void *addr, size_t len); > extern void __clean_dcache_area_pou(void *addr, size_t len); > extern long __flush_cache_user_range(unsigned long start, unsigned long end); > extern void sync_icache_aliases(void *kaddr, unsigned long len); > +extern void __flush_l1_dcache_way(phys_addr_t ptr); > > static inline void flush_cache_mm(struct mm_struct *mm) > { > diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S > index 7f1dbe9..5e65c20 100644 > --- a/arch/arm64/mm/cache.S > +++ b/arch/arm64/mm/cache.S > @@ -221,3 +221,38 @@ ENTRY(__dma_unmap_area) > b.ne __dma_inv_area > ret > ENDPIPROC(__dma_unmap_area) > + > +/* > + * Flush L1 dcache by way, using physical address to find sets > + * > + * __flush_l1_dcache_way(ptr) > + * - ptr - physical address to be flushed > + */ We don't have set/way maintenance in the kernel because its impossible to do correctly outside EL3's CPU power-on code. The ARM-ARM has a half page 'note' explaining the issues, under 'Performing cache maintenance instructions' in section "D3.4.8 A64 Cache maintenance instructions". If you have DDI0487B.b, its on Page D3-2020. These may also help: https://lkml.org/lkml/2016/3/21/190 https://events.static.linuxfound.org/sites/events/files/slides/slides_17.pdf https://www.linux.com/news/taming-chaos-modern-caches Why do you need to do this? There is no way to guarantee an address isn't in the cache. > +ENTRY(__flush_l1_dcache_way) > + msr csselr_el1, xzr /* select cache level 1 */ > + isb > + mrs x6, ccsidr_el1 > + and x2, x6, #7 > + add x2, x2, #4 /* x2 has log2(cache line size) */ > + mov x3, #0x3ff > + and x3, x3, x6, lsr #3 /* x3 has number of ways - 1 */ > + clz w5, w3 /* bit position of ways */ > + mov x4, #0x7fff > + and x4, x4, x6, lsr #13 /* x4 has number of sets - 1 */ > + clz x7, x4 > + lsr x0, x0, x2 > + lsl x0, x0, x7 > + lsr x0, x0, x7 /* x0 has the set for ptr */ > + > + mov x6, x3 > +loop_way: > + lsl x9, x3, x5 > + lsl x7, x0, x2 > + orr x9, x9, x7 > + dc cisw, x9 > + subs x6, x6, #1 > + b.ge loop_way > + dsb ish > + ret > + > +ENDPIPROC(__flush_l1_dcache_way) > diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile > index 0fd9ffa..6c21941 100644 > --- a/drivers/edac/Makefile > +++ b/drivers/edac/Makefile > @@ -78,3 +78,4 @@ obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o > obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o > obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o > obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o > +obj-$(CONFIG_EDAC_CORTEX_ARM64_L1_L2) += cortex_arm64_l1_l2.o > diff --git a/drivers/edac/cortex_arm64_l1_l2.c b/drivers/edac/cortex_arm64_l1_l2.c > new file mode 100644 > index 0000000..9bcc8e9 > --- /dev/null > +++ b/drivers/edac/cortex_arm64_l1_l2.c > @@ -0,0 +1,741 @@ > +/* > + * Cortex A57 and A53 EDAC L1 and L2 cache error detection > + * > + * Copyright (c) 2018, NXP Semiconductor > + * Author: York Sun > + * > + * Partially take from a similar driver by > + * Brijesh Singh > + * Copyright (c) 2015, Advanced Micro Devices > + * > + * SPDX-License-Identifier: GPL-2.0 > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "edac_module.h" > +#include "cortex_arm64_l1_l2.h" > + > +static int poll_msec = 1024; > +static long l1_ce_sw_inject_count, l1_ue_sw_inject_count; > +static long l2_ce_sw_inject_count, l2_ue_sw_inject_count; > +static struct cpumask compat_mask; > +static struct cpumask l1_ce_cpu_mask, l1_ue_cpu_mask; > +static struct cpumask l2_ce_cpu_mask, l2_ue_cpu_mask; > +static DEFINE_PER_CPU(unsigned long, actlr_en); > +static DEFINE_PER_CPU(unsigned long, l2ectlr_en); > +static DEFINE_PER_CPU(u64, cpumerr); > +static DEFINE_PER_CPU(u64, cpuactlr); > +static DEFINE_PER_CPU(u64, l2actlr); > +static DEFINE_PER_CPU(u64, l2merr); > +static DEFINE_PER_CPU(call_single_data_t, csd_check); > +static DEFINE_SPINLOCK(cortex_edac_lock); > + > +static inline void read_cpuactlr(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, S3_1_C15_C2_0" : "=r" (val)); I make ACTLR_EL1's encoding S3_0_1_0_1. What's this thing? Please create a define in your driver for these registers and use the read_sysreg_s() helpers. e.g: | #define A53_SYS_SOMETHING_EL1 sys_reg(3, 1, 15, 2, 0) | val = read_sysreg_s(A53_SYS_SOMETHING_EL1); > + per_cpu(cpuactlr, cpu) = val; this_cpu_write() ? > +} > + > +static inline void write_cpuactlr(int *mem) > +{ > + u64 val; > + int cpu; > + unsigned long flags; > + > + spin_lock_irqsave(&cortex_edac_lock, flags); > + cpu = smp_processor_id(); > + > + __flush_dcache_area(mem, 8); What is 8? > + asm volatile("mrs %0, S3_1_C15_C2_0" : "=r" (val)); > + val |= L1_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C2_0, %0" :: "r" (val)); > + asm volatile("isb sy"); Please use the macros, they're better than this asm-volatile: | dsb(sy); | isb(); ...and, they will also give you the compiler barrier you want here... > + /* make cache dirty */ > + *mem = 0xDEADBEEF; /* write to L1 data causes error right away */ You're doing this in C code. The compiler is allowed to re-order this write. As you don't read *mem, it can put it anywhere between spin_lock_irqsave()/spin_unlock_irqrestore(). It can even do it in two halves, or do it twice if it wants to. WRITE_ONCE() tells the compiler not split this write up, and you need compiler barriers as well as the CPU instruction barriers you have. The compiler doesn't know what 'isb' means. (this is why we already have those macros) But! You're doing all this to try and make '*mem =' the first write to the cache? We can't do this in C: the compiler may write registers to the stack. Even if it didn't, I don't think we can do this at all as we may take a firmware-interrupt, or a real-interrupt to a hypervisor here. What happens if a CPU (not necessarily this one) decides to read *mem? > + __flush_dcache_area(mem, 8); > + val &= ~L1_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C2_0, %0" :: "r" (val)); > + asm volatile("isb sy"); > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > +} > + > +static inline void read_l2actlr(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, S3_1_C15_C0_0" : "=r" (val)); > + per_cpu(l2actlr, cpu) = val; > +} > + > +static inline void write_l2actlr(int *mem) > +{ > + u64 val; > + unsigned long flags; > + > + spin_lock_irqsave(&cortex_edac_lock, flags); > + __flush_dcache_area(mem, 8); > + __flush_l1_dcache_way(virt_to_phys(mem)); > + asm volatile("mrs %0, S3_1_C15_C0_0" : "=r" (val)); > + val |= L2D_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C0_0, %0" :: "r" (val)); > + asm volatile("isb sy"); > + /* make cache dirty */ > + *mem = 0xDEADBEEF; /* Error will be reported when L2 is accessed. */ As above I don't think we can do this. What happens if another CPU accesses L2? > + __flush_l1_dcache_way(virt_to_phys(mem)); > + __flush_dcache_area(mem, 8); > + val &= ~L2D_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C0_0, %0" :: "r" (val)); > + asm volatile("isb sy"); > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > +} > + > +static inline void write_l2ectlr_el1(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, S3_1_C11_C0_3" : "=r" (val)); > + if (val & L2_ERR_INT) { > + pr_debug("l2ectlr_el1 on cpu %d reads 0x%llx\n", cpu, val); > + val &= ~L2_ERR_INT; > + asm volatile("msr S3_1_C11_C0_3, %0" :: "r" (val)); > + } > +} Isn't this more like a reset L2_ERR_INT bit than 'write_l2ectlr_el1();? > + > +static inline void write_cpumerrsr_el1(u64 val) > +{ > + asm volatile("msr s3_1_c15_c2_2, %0" :: "r" (val)); > +} > + > +static void a53_allow_l1l2_err_inj(void *info) > +{ > + int cpu = smp_processor_id(); > + struct arm_smccc_res res; > + unsigned long flags; > + > + pr_debug("%s: cpu is %d\n", __func__, cpu); > + spin_lock_irqsave(&cortex_edac_lock, flags); > + arm_smccc_smc(SIP_ALLOW_L1L2_ERR_32, 0, 0, 0, 0, 0, 0, 0, &res); Where is this call defined? (Its standardised somewhere right?) How do we know firmware implements it? How do we know 'SMC' is the SMCCC conduit to use? This will undef if its run in a virtual machine... > + per_cpu(actlr_en, cpu) = res.a0; > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > + pr_debug("%s: return is %ld\n", __func__, res.a0); > +} > + > +static void a53_allow_l1l2_err_irq_clr(void *info) > +{ > + int cpu = smp_processor_id(); > + struct arm_smccc_res res; > + unsigned long flags; > + > + pr_debug("%s: cpu is %d\n", __func__, cpu); > + spin_lock_irqsave(&cortex_edac_lock, flags); > + arm_smccc_smc(SIP_ALLOW_L2_CLR_32, 0, 0, 0, 0, 0, 0, 0, &res); > + per_cpu(l2ectlr_en, cpu) = res.a0; > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > + pr_debug("%s: return is %ld\n", __func__, res.a0); > +} > + > +static inline void read_cpumerrsr_el1(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, s3_1_c15_c2_2" : "=r" (val)); > + per_cpu(cpumerr, cpu) = val; > + if (val & ~CPUMERRSR_RAMID_MASK) { /* Skip RAMID */ > + pr_debug("cpu %d reads cpumerrsr_el1 0x%llx\n", cpu, val); > + /* clear the register since we already stored it */ > + write_cpumerrsr_el1(0); > + } else if (l1_ce_sw_inject_count > 0) { > + l1_ce_sw_inject_count--; > + pr_debug("inject correctable errors to cpu %d\n", cpu); > + per_cpu(cpumerr, cpu) = (1UL << 31); /* valid bit */ > + } else if (l1_ue_sw_inject_count > 0) { > + l1_ue_sw_inject_count--; > + pr_debug("inject Uncorrectable errors to cpu %d\n", cpu); > + per_cpu(cpumerr, cpu) = (1UL << 63) | (1UL << 31); > + } > +} > + > +static inline void write_l2merrsr_el1(u64 val) > +{ > + asm volatile("msr s3_1_c15_c2_3, %0" :: "r" (val)); > +} > + > +static inline void read_l2merrsr_el1(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, s3_1_c15_c2_3" : "=r" (val)); > + per_cpu(l2merr, cpu) = val; > + if (val & ~L2MERRSR_RAMID_MASK) { /* Skip RAMID */ > + pr_debug("cpu %d reads l2merrsr_el1 0x%llx\n", cpu, val); > + /* clear the register since we already stored it */ > + write_l2merrsr_el1(0); > + } else if (l2_ce_sw_inject_count > 0) { > + l2_ce_sw_inject_count--; > + pr_debug("inject correctable errors to L2 on cpu %d\n", cpu); > + per_cpu(l2merr, cpu) = (1UL << 31); /* valid bit */ Please create named macros for these bits: | #define A53_L2MERR_VALID BIT(31) > + } else if (l2_ue_sw_inject_count > 0) { > + l2_ue_sw_inject_count--; > + pr_debug("inject Uncorrectable errors to L2 on cpu %d\n", cpu); > + per_cpu(l2merr, cpu) = (1UL << 63) | (1UL << 31); > + } > +} > +static void read_errors(void *info) > +{ > + read_cpumerrsr_el1(info); > + read_l2merrsr_el1(info); > + write_l2ectlr_el1(info); > +} > + > + > +/* Returns 0 for no error > + * -1 for uncorrectable error(s) > + * 1 for correctable error(s) Is both a possibility? > + */ > +static int parse_cpumerrsr(unsigned int cpu) > +{ > + u64 val = per_cpu(cpumerr, cpu); > + > + /* check if we have valid error before continuing */ > + if (!CPUMERRSR_EL1_VALID(val)) > + return 0; > + > + cortex_printk(KERN_INFO, "CPU %d ", cpu); > + > + switch (CPUMERRSR_EL1_RAMID(val)) { > + case L1_I_TAG_RAM: > + pr_cont("L1-I Tag RAM"); > + break; > + case L1_I_DATA_RAM: > + pr_cont("L1-I Data RAM"); > + break; > + case L1_D_TAG_RAM: > + pr_cont("L1-D Tag RAM"); > + break; > + case L1_D_DATA_RAM: > + pr_cont("L1-D Data RAM"); > + break; > + case L1_D_DIRTY_RAM: > + pr_cont("L1 Dirty RAM"); > + break; > + case TLB_RAM: > + pr_cont("TLB RAM"); > + break; > + default: > + pr_cont("unknown"); > + break; > + } > + pr_cont(" error(s) detected\n"); > + > + if (CPUMERRSR_EL1_FATAL(val)) { > + cortex_printk(KERN_INFO, > + "CPU %d L1 fatal error(s) detected (0x%llx)\n", > + cpu, val); > + return -1; > + } > + > + return 1; > +} > + > +static int parse_l2merrsr(unsigned int cpu) > +{ > + u64 val = per_cpu(l2merr, cpu); > + > + /* check if we have valid error before continuing */ > + if (!L2MERRSR_EL1_VALID(val)) > + return 0; > + > + cortex_printk(KERN_INFO, "CPU %d L2 %s error(s) detected (0x%llx)\n", > + cpu, L2MERRSR_EL1_FATAL(val) ? "fatal" : "", val); > + > + return L2MERRSR_EL1_FATAL(val) ? -1 : 1; > +} > + > +#define MESSAGE_SIZE 40 > +static void cortex_arm64_edac_check(struct edac_device_ctl_info *edac_ctl) > +{ > + int cpu; > + char msg[MESSAGE_SIZE]; > + call_single_data_t *csd; > + > + get_online_cpus(); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + csd = &per_cpu(csd_check, cpu); > + csd->func = read_errors; > + csd->info = NULL; > + csd->flags = 0; > + /* Read CPU L1 error */ > + smp_call_function_single_async(cpu, csd); > + /* Wait until flags cleared */ > + smp_cond_load_acquire(&csd->flags, !VAL); So this CPU waits in IRQ context for each CPU in compat_mask to do the work. What happens if another driver does the same? Won't this deadlock? I think the whole point of this smp_call_function_single_async() call is you don't wait in IRQ context for it to finish. The problem here is the IRQ isn't a per-cpu PPI, but the register for acknowledging the interrupt is a per-cpu system register. Can we ask the irqchip to disable the IRQ until we've done the per-cpu work to clear it? > + } > + put_online_cpus(); > + > + cpumask_clear(&l1_ce_cpu_mask); > + cpumask_clear(&l1_ue_cpu_mask); > + cpumask_clear(&l2_ce_cpu_mask); > + cpumask_clear(&l2_ue_cpu_mask); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + switch (parse_cpumerrsr(cpu)) { > + case -1: > + /* fatal error */ > + cpumask_set_cpu(cpu, &l1_ue_cpu_mask); > + break; > + case 1: > + /* correctable error(s) */ > + cpumask_set_cpu(cpu, &l1_ce_cpu_mask); > + break; > + case 0: > + /* fall through */ > + default: > + break; > + } > + switch (parse_l2merrsr(cpu)) { > + case -1: > + /* fatal error */ > + cpumask_set_cpu(cpu, &l2_ue_cpu_mask); > + break; > + case 1: > + /* correctable error(s) */ > + cpumask_set_cpu(cpu, &l2_ce_cpu_mask); > + break; > + case 0: > + /* fall through */ > + default: > + break; > + } > + } > + > + for_each_cpu(cpu, &l1_ue_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Fatal error(s) on CPU %d\n", cpu); > + edac_device_handle_ue(edac_ctl, 0, 0, msg); > + } > + > + for_each_cpu(cpu, &l1_ce_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Correctable error(s) on CPU %d\n", cpu); > + edac_device_handle_ce(edac_ctl, 0, 0, msg); > + } > + > + for_each_cpu(cpu, &l2_ue_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Fatal error(s) on CPU %d\n", cpu); > + edac_device_handle_ue(edac_ctl, 0, 1, msg); > + } > + > + for_each_cpu(cpu, &l2_ce_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Correctable error(s) on CPU %d\n", cpu); > + edac_device_handle_ce(edac_ctl, 0, 1, msg); > + } > + > + if (!cpumask_empty(&l1_ce_cpu_mask) || > + !cpumask_empty(&l2_ce_cpu_mask) || > + !cpumask_empty(&l1_ue_cpu_mask) || > + !cpumask_empty(&l2_ue_cpu_mask)) { > + if (poll_msec > MIN_POLL_MSEC) { > + poll_msec >>= 1; > + edac_device_reset_delay_period(edac_ctl, poll_msec); > + } else { > + cortex_printk(KERN_CRIT, > + "Excessive correctable errors\n"); > + } > + } else { > + if (poll_msec < MAX_POLL_MSEC) { > + poll_msec <<= 1; > + edac_device_reset_delay_period(edac_ctl, poll_msec); > + } > + } > +} [...] > +static irqreturn_t cortex_edac_isr(int irq, void *dev_id) > +{ > + struct edac_device_ctl_info *edac_ctl = dev_id; > + > + pr_debug("Got IRQ\n"); > + cortex_arm64_edac_check(edac_ctl); > + > + return IRQ_HANDLED; > +} > + > +static int cortex_arm64_edac_probe(struct platform_device *pdev) > +{ > + int i, rc, cpu, num_attr; > + struct edac_device_ctl_info *edac_ctl; > + struct device *dev = &pdev->dev; > + struct cortex_pdata *pdata; > + struct device_node *np, *dn = pdev->dev.of_node; > + struct of_phandle_iterator it; > + struct edac_dev_sysfs_attribute *attr; > + const __be32 *cell; > + u64 mpidr; > + > + cpumask_clear(&compat_mask); > + of_for_each_phandle(&it, rc, dn, "cpus", NULL, 0) { > + np = it.node; > + cell = of_get_property(np, "reg", NULL); > + if (!cell) { > + pr_err("%pOF: missing reg property\n", np); > + continue; > + } > + mpidr = of_read_number(cell, of_n_addr_cells(np)); > + cpu = get_logical_index(mpidr); > + if (cpu < 0) { > + pr_err("Bad CPU number for mpidr 0x%llx", mpidr); > + continue; > + } > + cpumask_set_cpu(cpu, &compat_mask); > + } > + > + pr_debug("compat_mask is %*pbl\n", cpumask_pr_args(&compat_mask)); > + > + if (of_device_is_compatible(dn, "arm,cortex-a53-edac")) { > + num_attr = ARRAY_SIZE(device_sysfs_attr); > + get_online_cpus(); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + smp_call_function_single(cpu, a53_allow_l1l2_err_inj, NULL, 1); > + if (per_cpu(actlr_en, cpu)) { > + pr_err("Failed to enable hardware error injection (%ld)\n", > + per_cpu(actlr_en, cpu)); > + num_attr -= 2; > + break; > + } > + } > + put_online_cpus(); > + } else { > + num_attr = ARRAY_SIZE(device_sysfs_attr) - 2; > + } > + > + /* POLL mode is used to detect correctable errors */ > + edac_op_state = EDAC_OPSTATE_POLL; > + > + edac_ctl = edac_device_alloc_ctl_info(sizeof(*pdata), "cpu_cache", > + 1, "L", 2, 1, NULL, 0, > + edac_device_alloc_index()); > + if (IS_ERR(edac_ctl)) > + return -ENOMEM; > + > + pdata = edac_ctl->pvt_info; > + attr = devm_kzalloc(dev, > + sizeof(struct edac_dev_sysfs_attribute) * num_attr, > + GFP_KERNEL); > + if (!attr) { > + rc = -ENOMEM; > + goto out_dev; > + } > + > + for (i = 0; i < num_attr - 1; i++) { > + attr[i].attr.name = device_sysfs_attr[i].attr.name; > + attr[i].attr.mode = device_sysfs_attr[i].attr.mode; > + attr[i].show = device_sysfs_attr[i].show; > + attr[i].store = device_sysfs_attr[i].store; > + } > + edac_ctl->sysfs_attributes = attr; > + > + rc = of_count_phandle_with_args(dn, "cpus", NULL); > + if (rc <= 0) { > + pr_err("Invalid number of phandles in 'cpus'\n"); > + rc = -EINVAL; > + goto out_dev; > + } > + pdata->irq = platform_get_irq(pdev, 0); > + pr_debug("irq is %d\n", pdata->irq); > + > + edac_ctl->poll_msec = poll_msec; > + edac_ctl->edac_check = cortex_arm64_edac_check; > + edac_ctl->dev = dev; > + edac_ctl->mod_name = dev_name(dev); > + edac_ctl->dev_name = dev_name(dev); > + edac_ctl->ctl_name = EDAC_MOD_STR; > + dev_set_drvdata(dev, edac_ctl); > + > + rc = edac_device_add_device(edac_ctl); > + if (rc) > + goto out_dev; > + > + pdata->mem = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL); > + if (!pdata->mem) > + goto out_mem; > + > + if (pdata->irq) { > + get_online_cpus(); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + smp_call_function_single(cpu, > + a53_allow_l1l2_err_irq_clr, > + NULL, > + 1); How do you know this is only called on the A53s? You added all the CPUs to compat_mask. It may be worth having separate probe calls for A53 and A57. Thanks, James > + if (per_cpu(l2ectlr_en, cpu)) { > + pr_err("Failed to enable interrupt clearing (%ld)\n", > + per_cpu(l2ectlr_en, cpu)); > + rc = -EACCES; > + break; > + } > + } > + put_online_cpus(); > + > + if (!rc) { > + rc = devm_request_irq(dev, pdata->irq, cortex_edac_isr, > + 0, "cortex_edac error", edac_ctl); > + if (rc < 0) { > + pr_err("%s: Unable to request irq %d for cortex edac error\n", > + __func__, pdata->irq); > + goto out_irq; > + } > + } > + } > + > + return 0; > + > +out_mem: > +out_irq: > + edac_device_del_device(edac_ctl->dev); > + > +out_dev: > + edac_device_free_ctl_info(edac_ctl); > + > + return rc; > +} > + > +static int cortex_arm64_edac_remove(struct platform_device *pdev) > +{ > + struct edac_device_ctl_info *edac_ctl = dev_get_drvdata(&pdev->dev); > + > + edac_device_del_device(edac_ctl->dev); > + edac_device_free_ctl_info(edac_ctl); > + > + return 0; > +} > + > +static const struct of_device_id cortex_arm64_edac_of_match[] = { > + { .compatible = "arm,cortex-a57-edac" }, > + { .compatible = "arm,cortex-a53-edac" }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, cortex_arm64_edac_of_match); > + > +static struct platform_driver cortex_arm64_edac_driver = { > + .probe = cortex_arm64_edac_probe, > + .remove = cortex_arm64_edac_remove, > + .driver = { > + .name = EDAC_MOD_STR, > + .of_match_table = cortex_arm64_edac_of_match, > + }, > +}; > +module_platform_driver(cortex_arm64_edac_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("York Sun "); > +MODULE_DESCRIPTION("Cortex A57 and A53 L1 and L2 cache EDAC driver"); From mboxrd@z Thu Jan 1 00:00:00 1970 From: James Morse Subject: Re: [PATCH RFC 1/2] drivers/edac: Add L1 and L2 error detection for A53 and A57 Date: Thu, 15 Mar 2018 13:33:52 +0000 Message-ID: <5AAA7640.3010506@arm.com> References: <1521073067-24348-1-git-send-email-york.sun@nxp.com> Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1521073067-24348-1-git-send-email-york.sun@nxp.com> Sender: linux-kernel-owner@vger.kernel.org To: York Sun Cc: bp@alien8.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, "linux-arm-kernel@lists.infradead.org" List-Id: devicetree@vger.kernel.org Hi York, You have a DT binding in here, please CC the devicetree list. You're touching code under arch/arm64, so you need the arm list too. get_maintainer.pl will take your patch and give you the list of which lists and maintainers to CC. (I've added those lists, the full patch is here: https://patchwork.kernel.org/patch/10283783/ ) Some comments below, I haven't looked in to edac or the manuals for A53/A57. On 15/03/18 00:17, York Sun wrote: > Add error detection for A53 and A57 cores. Hardware error injection > is supported on A53. Software error injection is supported on both. > For hardware error injection on A53 to work, proper access to > L2ACTLR_EL1, CPUACTLR_EL1 needs to be granted by EL3 firmware. This > is done by making an SMC call in the driver. Failure to enable access > disables hardware error injection. For error interrupt to work, > another SMC call enables access to L2ECTLR_EL1. Failure to enable > access disables interrupt for error reporting. This is tricky as there are shipped systems out there without these SMC calls. They need to be discovered in some way. We can't even assume firmware has PSCI, it has to be discovered via APCI/DT. I think it will be cleaner for the presence of this device/compatible to indicate that the registers are enabled for the normal-world, instead of having the OS try to call into firmware to enable it. > Signed-off-by: York Sun > --- > .../devicetree/bindings/edac/cortex-arm64-edac.txt | 37 + > arch/arm64/include/asm/cacheflush.h | 1 + > arch/arm64/mm/cache.S | 35 + > drivers/edac/Kconfig | 6 + > drivers/edac/Makefile | 1 + > drivers/edac/cortex_arm64_l1_l2.c | 741 +++++++++++++++++++++ > drivers/edac/cortex_arm64_l1_l2.h | 55 ++ > 7 files changed, 876 insertions(+) > create mode 100644 Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt > create mode 100644 drivers/edac/cortex_arm64_l1_l2.c > create mode 100644 drivers/edac/cortex_arm64_l1_l2.h > > diff --git a/Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt b/Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt > new file mode 100644 > index 0000000..74a1c2f > --- /dev/null > +++ b/Documentation/devicetree/bindings/edac/cortex-arm64-edac.txt > @@ -0,0 +1,37 @@ > +ARM Cortex A57 and A53 L1/L2 cache error reporting > + > +CPU Memory Error Syndrome and L2 Memory Error Syndrome registers can be used > +for checking L1 and L2 memory errors. However, only A53 supports double-bit > +error injection to L1 and L2 memory. This driver uses the hardware error > +injection when available, but also provides a way to inject errors by > +software. Both A53 and A57 supports interrupt when multi-bit errors happen. > +To use hardware error injection and the interrupt, proper access needs to be > +granted in ACTLR_EL3 (and/or ACTLR_EL2) register by EL3 firmware SMC call. How can Linux know whether firmware toggled these bits? How can it know if it needs to make an SMC call to do the work? This looks like platform policy, I'm not sure how this gets described... > +Correctable errors do not trigger such interrupt. This driver uses dynamic > +polling internal to check for errors. The more errors detected, the more > +frequently it polls. Combining with interrupt, this driver can detect > +correctable and uncorrectable errors. However, if the uncorrectable errors > +cause system abort exception, this drivr is not able to report errors in time. > + > +The following section describes the Cortex A57/A53 EDAC DT node binding. > + > +Required properties: > +- compatible: Should be "arm,cortex-a57-edac" or "arm,cortex-a53-edac" > +- cpus: Should be a list of compatible cores > + > +Optional properties: > +- interrupts: Interrupt number if supported > + > +Example: > + edac { > + compatible = "arm,cortex-a53-edac"; > + cpus = <&cpu0>, > + <&cpu1>, > + <&cpu2>, > + <&cpu3>; > + interrupts = <0 108 0x4>; > + > + }; > + > diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h > index 76d1cc8..f1cd090 100644 > --- a/arch/arm64/include/asm/cacheflush.h > +++ b/arch/arm64/include/asm/cacheflush.h > @@ -73,6 +73,7 @@ extern void __clean_dcache_area_pop(void *addr, size_t len); > extern void __clean_dcache_area_pou(void *addr, size_t len); > extern long __flush_cache_user_range(unsigned long start, unsigned long end); > extern void sync_icache_aliases(void *kaddr, unsigned long len); > +extern void __flush_l1_dcache_way(phys_addr_t ptr); > > static inline void flush_cache_mm(struct mm_struct *mm) > { > diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S > index 7f1dbe9..5e65c20 100644 > --- a/arch/arm64/mm/cache.S > +++ b/arch/arm64/mm/cache.S > @@ -221,3 +221,38 @@ ENTRY(__dma_unmap_area) > b.ne __dma_inv_area > ret > ENDPIPROC(__dma_unmap_area) > + > +/* > + * Flush L1 dcache by way, using physical address to find sets > + * > + * __flush_l1_dcache_way(ptr) > + * - ptr - physical address to be flushed > + */ We don't have set/way maintenance in the kernel because its impossible to do correctly outside EL3's CPU power-on code. The ARM-ARM has a half page 'note' explaining the issues, under 'Performing cache maintenance instructions' in section "D3.4.8 A64 Cache maintenance instructions". If you have DDI0487B.b, its on Page D3-2020. These may also help: https://lkml.org/lkml/2016/3/21/190 https://events.static.linuxfound.org/sites/events/files/slides/slides_17.pdf https://www.linux.com/news/taming-chaos-modern-caches Why do you need to do this? There is no way to guarantee an address isn't in the cache. > +ENTRY(__flush_l1_dcache_way) > + msr csselr_el1, xzr /* select cache level 1 */ > + isb > + mrs x6, ccsidr_el1 > + and x2, x6, #7 > + add x2, x2, #4 /* x2 has log2(cache line size) */ > + mov x3, #0x3ff > + and x3, x3, x6, lsr #3 /* x3 has number of ways - 1 */ > + clz w5, w3 /* bit position of ways */ > + mov x4, #0x7fff > + and x4, x4, x6, lsr #13 /* x4 has number of sets - 1 */ > + clz x7, x4 > + lsr x0, x0, x2 > + lsl x0, x0, x7 > + lsr x0, x0, x7 /* x0 has the set for ptr */ > + > + mov x6, x3 > +loop_way: > + lsl x9, x3, x5 > + lsl x7, x0, x2 > + orr x9, x9, x7 > + dc cisw, x9 > + subs x6, x6, #1 > + b.ge loop_way > + dsb ish > + ret > + > +ENDPIPROC(__flush_l1_dcache_way) > diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile > index 0fd9ffa..6c21941 100644 > --- a/drivers/edac/Makefile > +++ b/drivers/edac/Makefile > @@ -78,3 +78,4 @@ obj-$(CONFIG_EDAC_THUNDERX) += thunderx_edac.o > obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o > obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o > obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o > +obj-$(CONFIG_EDAC_CORTEX_ARM64_L1_L2) += cortex_arm64_l1_l2.o > diff --git a/drivers/edac/cortex_arm64_l1_l2.c b/drivers/edac/cortex_arm64_l1_l2.c > new file mode 100644 > index 0000000..9bcc8e9 > --- /dev/null > +++ b/drivers/edac/cortex_arm64_l1_l2.c > @@ -0,0 +1,741 @@ > +/* > + * Cortex A57 and A53 EDAC L1 and L2 cache error detection > + * > + * Copyright (c) 2018, NXP Semiconductor > + * Author: York Sun > + * > + * Partially take from a similar driver by > + * Brijesh Singh > + * Copyright (c) 2015, Advanced Micro Devices > + * > + * SPDX-License-Identifier: GPL-2.0 > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "edac_module.h" > +#include "cortex_arm64_l1_l2.h" > + > +static int poll_msec = 1024; > +static long l1_ce_sw_inject_count, l1_ue_sw_inject_count; > +static long l2_ce_sw_inject_count, l2_ue_sw_inject_count; > +static struct cpumask compat_mask; > +static struct cpumask l1_ce_cpu_mask, l1_ue_cpu_mask; > +static struct cpumask l2_ce_cpu_mask, l2_ue_cpu_mask; > +static DEFINE_PER_CPU(unsigned long, actlr_en); > +static DEFINE_PER_CPU(unsigned long, l2ectlr_en); > +static DEFINE_PER_CPU(u64, cpumerr); > +static DEFINE_PER_CPU(u64, cpuactlr); > +static DEFINE_PER_CPU(u64, l2actlr); > +static DEFINE_PER_CPU(u64, l2merr); > +static DEFINE_PER_CPU(call_single_data_t, csd_check); > +static DEFINE_SPINLOCK(cortex_edac_lock); > + > +static inline void read_cpuactlr(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, S3_1_C15_C2_0" : "=r" (val)); I make ACTLR_EL1's encoding S3_0_1_0_1. What's this thing? Please create a define in your driver for these registers and use the read_sysreg_s() helpers. e.g: | #define A53_SYS_SOMETHING_EL1 sys_reg(3, 1, 15, 2, 0) | val = read_sysreg_s(A53_SYS_SOMETHING_EL1); > + per_cpu(cpuactlr, cpu) = val; this_cpu_write() ? > +} > + > +static inline void write_cpuactlr(int *mem) > +{ > + u64 val; > + int cpu; > + unsigned long flags; > + > + spin_lock_irqsave(&cortex_edac_lock, flags); > + cpu = smp_processor_id(); > + > + __flush_dcache_area(mem, 8); What is 8? > + asm volatile("mrs %0, S3_1_C15_C2_0" : "=r" (val)); > + val |= L1_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C2_0, %0" :: "r" (val)); > + asm volatile("isb sy"); Please use the macros, they're better than this asm-volatile: | dsb(sy); | isb(); ...and, they will also give you the compiler barrier you want here... > + /* make cache dirty */ > + *mem = 0xDEADBEEF; /* write to L1 data causes error right away */ You're doing this in C code. The compiler is allowed to re-order this write. As you don't read *mem, it can put it anywhere between spin_lock_irqsave()/spin_unlock_irqrestore(). It can even do it in two halves, or do it twice if it wants to. WRITE_ONCE() tells the compiler not split this write up, and you need compiler barriers as well as the CPU instruction barriers you have. The compiler doesn't know what 'isb' means. (this is why we already have those macros) But! You're doing all this to try and make '*mem =' the first write to the cache? We can't do this in C: the compiler may write registers to the stack. Even if it didn't, I don't think we can do this at all as we may take a firmware-interrupt, or a real-interrupt to a hypervisor here. What happens if a CPU (not necessarily this one) decides to read *mem? > + __flush_dcache_area(mem, 8); > + val &= ~L1_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C2_0, %0" :: "r" (val)); > + asm volatile("isb sy"); > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > +} > + > +static inline void read_l2actlr(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, S3_1_C15_C0_0" : "=r" (val)); > + per_cpu(l2actlr, cpu) = val; > +} > + > +static inline void write_l2actlr(int *mem) > +{ > + u64 val; > + unsigned long flags; > + > + spin_lock_irqsave(&cortex_edac_lock, flags); > + __flush_dcache_area(mem, 8); > + __flush_l1_dcache_way(virt_to_phys(mem)); > + asm volatile("mrs %0, S3_1_C15_C0_0" : "=r" (val)); > + val |= L2D_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C0_0, %0" :: "r" (val)); > + asm volatile("isb sy"); > + /* make cache dirty */ > + *mem = 0xDEADBEEF; /* Error will be reported when L2 is accessed. */ As above I don't think we can do this. What happens if another CPU accesses L2? > + __flush_l1_dcache_way(virt_to_phys(mem)); > + __flush_dcache_area(mem, 8); > + val &= ~L2D_ERR_INJ_EN; > + asm volatile("dsb sy"); > + asm volatile("msr S3_1_C15_C0_0, %0" :: "r" (val)); > + asm volatile("isb sy"); > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > +} > + > +static inline void write_l2ectlr_el1(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, S3_1_C11_C0_3" : "=r" (val)); > + if (val & L2_ERR_INT) { > + pr_debug("l2ectlr_el1 on cpu %d reads 0x%llx\n", cpu, val); > + val &= ~L2_ERR_INT; > + asm volatile("msr S3_1_C11_C0_3, %0" :: "r" (val)); > + } > +} Isn't this more like a reset L2_ERR_INT bit than 'write_l2ectlr_el1();? > + > +static inline void write_cpumerrsr_el1(u64 val) > +{ > + asm volatile("msr s3_1_c15_c2_2, %0" :: "r" (val)); > +} > + > +static void a53_allow_l1l2_err_inj(void *info) > +{ > + int cpu = smp_processor_id(); > + struct arm_smccc_res res; > + unsigned long flags; > + > + pr_debug("%s: cpu is %d\n", __func__, cpu); > + spin_lock_irqsave(&cortex_edac_lock, flags); > + arm_smccc_smc(SIP_ALLOW_L1L2_ERR_32, 0, 0, 0, 0, 0, 0, 0, &res); Where is this call defined? (Its standardised somewhere right?) How do we know firmware implements it? How do we know 'SMC' is the SMCCC conduit to use? This will undef if its run in a virtual machine... > + per_cpu(actlr_en, cpu) = res.a0; > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > + pr_debug("%s: return is %ld\n", __func__, res.a0); > +} > + > +static void a53_allow_l1l2_err_irq_clr(void *info) > +{ > + int cpu = smp_processor_id(); > + struct arm_smccc_res res; > + unsigned long flags; > + > + pr_debug("%s: cpu is %d\n", __func__, cpu); > + spin_lock_irqsave(&cortex_edac_lock, flags); > + arm_smccc_smc(SIP_ALLOW_L2_CLR_32, 0, 0, 0, 0, 0, 0, 0, &res); > + per_cpu(l2ectlr_en, cpu) = res.a0; > + spin_unlock_irqrestore(&cortex_edac_lock, flags); > + pr_debug("%s: return is %ld\n", __func__, res.a0); > +} > + > +static inline void read_cpumerrsr_el1(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, s3_1_c15_c2_2" : "=r" (val)); > + per_cpu(cpumerr, cpu) = val; > + if (val & ~CPUMERRSR_RAMID_MASK) { /* Skip RAMID */ > + pr_debug("cpu %d reads cpumerrsr_el1 0x%llx\n", cpu, val); > + /* clear the register since we already stored it */ > + write_cpumerrsr_el1(0); > + } else if (l1_ce_sw_inject_count > 0) { > + l1_ce_sw_inject_count--; > + pr_debug("inject correctable errors to cpu %d\n", cpu); > + per_cpu(cpumerr, cpu) = (1UL << 31); /* valid bit */ > + } else if (l1_ue_sw_inject_count > 0) { > + l1_ue_sw_inject_count--; > + pr_debug("inject Uncorrectable errors to cpu %d\n", cpu); > + per_cpu(cpumerr, cpu) = (1UL << 63) | (1UL << 31); > + } > +} > + > +static inline void write_l2merrsr_el1(u64 val) > +{ > + asm volatile("msr s3_1_c15_c2_3, %0" :: "r" (val)); > +} > + > +static inline void read_l2merrsr_el1(void *info) > +{ > + u64 val; > + int cpu = smp_processor_id(); > + > + asm volatile("mrs %0, s3_1_c15_c2_3" : "=r" (val)); > + per_cpu(l2merr, cpu) = val; > + if (val & ~L2MERRSR_RAMID_MASK) { /* Skip RAMID */ > + pr_debug("cpu %d reads l2merrsr_el1 0x%llx\n", cpu, val); > + /* clear the register since we already stored it */ > + write_l2merrsr_el1(0); > + } else if (l2_ce_sw_inject_count > 0) { > + l2_ce_sw_inject_count--; > + pr_debug("inject correctable errors to L2 on cpu %d\n", cpu); > + per_cpu(l2merr, cpu) = (1UL << 31); /* valid bit */ Please create named macros for these bits: | #define A53_L2MERR_VALID BIT(31) > + } else if (l2_ue_sw_inject_count > 0) { > + l2_ue_sw_inject_count--; > + pr_debug("inject Uncorrectable errors to L2 on cpu %d\n", cpu); > + per_cpu(l2merr, cpu) = (1UL << 63) | (1UL << 31); > + } > +} > +static void read_errors(void *info) > +{ > + read_cpumerrsr_el1(info); > + read_l2merrsr_el1(info); > + write_l2ectlr_el1(info); > +} > + > + > +/* Returns 0 for no error > + * -1 for uncorrectable error(s) > + * 1 for correctable error(s) Is both a possibility? > + */ > +static int parse_cpumerrsr(unsigned int cpu) > +{ > + u64 val = per_cpu(cpumerr, cpu); > + > + /* check if we have valid error before continuing */ > + if (!CPUMERRSR_EL1_VALID(val)) > + return 0; > + > + cortex_printk(KERN_INFO, "CPU %d ", cpu); > + > + switch (CPUMERRSR_EL1_RAMID(val)) { > + case L1_I_TAG_RAM: > + pr_cont("L1-I Tag RAM"); > + break; > + case L1_I_DATA_RAM: > + pr_cont("L1-I Data RAM"); > + break; > + case L1_D_TAG_RAM: > + pr_cont("L1-D Tag RAM"); > + break; > + case L1_D_DATA_RAM: > + pr_cont("L1-D Data RAM"); > + break; > + case L1_D_DIRTY_RAM: > + pr_cont("L1 Dirty RAM"); > + break; > + case TLB_RAM: > + pr_cont("TLB RAM"); > + break; > + default: > + pr_cont("unknown"); > + break; > + } > + pr_cont(" error(s) detected\n"); > + > + if (CPUMERRSR_EL1_FATAL(val)) { > + cortex_printk(KERN_INFO, > + "CPU %d L1 fatal error(s) detected (0x%llx)\n", > + cpu, val); > + return -1; > + } > + > + return 1; > +} > + > +static int parse_l2merrsr(unsigned int cpu) > +{ > + u64 val = per_cpu(l2merr, cpu); > + > + /* check if we have valid error before continuing */ > + if (!L2MERRSR_EL1_VALID(val)) > + return 0; > + > + cortex_printk(KERN_INFO, "CPU %d L2 %s error(s) detected (0x%llx)\n", > + cpu, L2MERRSR_EL1_FATAL(val) ? "fatal" : "", val); > + > + return L2MERRSR_EL1_FATAL(val) ? -1 : 1; > +} > + > +#define MESSAGE_SIZE 40 > +static void cortex_arm64_edac_check(struct edac_device_ctl_info *edac_ctl) > +{ > + int cpu; > + char msg[MESSAGE_SIZE]; > + call_single_data_t *csd; > + > + get_online_cpus(); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + csd = &per_cpu(csd_check, cpu); > + csd->func = read_errors; > + csd->info = NULL; > + csd->flags = 0; > + /* Read CPU L1 error */ > + smp_call_function_single_async(cpu, csd); > + /* Wait until flags cleared */ > + smp_cond_load_acquire(&csd->flags, !VAL); So this CPU waits in IRQ context for each CPU in compat_mask to do the work. What happens if another driver does the same? Won't this deadlock? I think the whole point of this smp_call_function_single_async() call is you don't wait in IRQ context for it to finish. The problem here is the IRQ isn't a per-cpu PPI, but the register for acknowledging the interrupt is a per-cpu system register. Can we ask the irqchip to disable the IRQ until we've done the per-cpu work to clear it? > + } > + put_online_cpus(); > + > + cpumask_clear(&l1_ce_cpu_mask); > + cpumask_clear(&l1_ue_cpu_mask); > + cpumask_clear(&l2_ce_cpu_mask); > + cpumask_clear(&l2_ue_cpu_mask); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + switch (parse_cpumerrsr(cpu)) { > + case -1: > + /* fatal error */ > + cpumask_set_cpu(cpu, &l1_ue_cpu_mask); > + break; > + case 1: > + /* correctable error(s) */ > + cpumask_set_cpu(cpu, &l1_ce_cpu_mask); > + break; > + case 0: > + /* fall through */ > + default: > + break; > + } > + switch (parse_l2merrsr(cpu)) { > + case -1: > + /* fatal error */ > + cpumask_set_cpu(cpu, &l2_ue_cpu_mask); > + break; > + case 1: > + /* correctable error(s) */ > + cpumask_set_cpu(cpu, &l2_ce_cpu_mask); > + break; > + case 0: > + /* fall through */ > + default: > + break; > + } > + } > + > + for_each_cpu(cpu, &l1_ue_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Fatal error(s) on CPU %d\n", cpu); > + edac_device_handle_ue(edac_ctl, 0, 0, msg); > + } > + > + for_each_cpu(cpu, &l1_ce_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Correctable error(s) on CPU %d\n", cpu); > + edac_device_handle_ce(edac_ctl, 0, 0, msg); > + } > + > + for_each_cpu(cpu, &l2_ue_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Fatal error(s) on CPU %d\n", cpu); > + edac_device_handle_ue(edac_ctl, 0, 1, msg); > + } > + > + for_each_cpu(cpu, &l2_ce_cpu_mask) { > + snprintf(msg, MESSAGE_SIZE, "Correctable error(s) on CPU %d\n", cpu); > + edac_device_handle_ce(edac_ctl, 0, 1, msg); > + } > + > + if (!cpumask_empty(&l1_ce_cpu_mask) || > + !cpumask_empty(&l2_ce_cpu_mask) || > + !cpumask_empty(&l1_ue_cpu_mask) || > + !cpumask_empty(&l2_ue_cpu_mask)) { > + if (poll_msec > MIN_POLL_MSEC) { > + poll_msec >>= 1; > + edac_device_reset_delay_period(edac_ctl, poll_msec); > + } else { > + cortex_printk(KERN_CRIT, > + "Excessive correctable errors\n"); > + } > + } else { > + if (poll_msec < MAX_POLL_MSEC) { > + poll_msec <<= 1; > + edac_device_reset_delay_period(edac_ctl, poll_msec); > + } > + } > +} [...] > +static irqreturn_t cortex_edac_isr(int irq, void *dev_id) > +{ > + struct edac_device_ctl_info *edac_ctl = dev_id; > + > + pr_debug("Got IRQ\n"); > + cortex_arm64_edac_check(edac_ctl); > + > + return IRQ_HANDLED; > +} > + > +static int cortex_arm64_edac_probe(struct platform_device *pdev) > +{ > + int i, rc, cpu, num_attr; > + struct edac_device_ctl_info *edac_ctl; > + struct device *dev = &pdev->dev; > + struct cortex_pdata *pdata; > + struct device_node *np, *dn = pdev->dev.of_node; > + struct of_phandle_iterator it; > + struct edac_dev_sysfs_attribute *attr; > + const __be32 *cell; > + u64 mpidr; > + > + cpumask_clear(&compat_mask); > + of_for_each_phandle(&it, rc, dn, "cpus", NULL, 0) { > + np = it.node; > + cell = of_get_property(np, "reg", NULL); > + if (!cell) { > + pr_err("%pOF: missing reg property\n", np); > + continue; > + } > + mpidr = of_read_number(cell, of_n_addr_cells(np)); > + cpu = get_logical_index(mpidr); > + if (cpu < 0) { > + pr_err("Bad CPU number for mpidr 0x%llx", mpidr); > + continue; > + } > + cpumask_set_cpu(cpu, &compat_mask); > + } > + > + pr_debug("compat_mask is %*pbl\n", cpumask_pr_args(&compat_mask)); > + > + if (of_device_is_compatible(dn, "arm,cortex-a53-edac")) { > + num_attr = ARRAY_SIZE(device_sysfs_attr); > + get_online_cpus(); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + smp_call_function_single(cpu, a53_allow_l1l2_err_inj, NULL, 1); > + if (per_cpu(actlr_en, cpu)) { > + pr_err("Failed to enable hardware error injection (%ld)\n", > + per_cpu(actlr_en, cpu)); > + num_attr -= 2; > + break; > + } > + } > + put_online_cpus(); > + } else { > + num_attr = ARRAY_SIZE(device_sysfs_attr) - 2; > + } > + > + /* POLL mode is used to detect correctable errors */ > + edac_op_state = EDAC_OPSTATE_POLL; > + > + edac_ctl = edac_device_alloc_ctl_info(sizeof(*pdata), "cpu_cache", > + 1, "L", 2, 1, NULL, 0, > + edac_device_alloc_index()); > + if (IS_ERR(edac_ctl)) > + return -ENOMEM; > + > + pdata = edac_ctl->pvt_info; > + attr = devm_kzalloc(dev, > + sizeof(struct edac_dev_sysfs_attribute) * num_attr, > + GFP_KERNEL); > + if (!attr) { > + rc = -ENOMEM; > + goto out_dev; > + } > + > + for (i = 0; i < num_attr - 1; i++) { > + attr[i].attr.name = device_sysfs_attr[i].attr.name; > + attr[i].attr.mode = device_sysfs_attr[i].attr.mode; > + attr[i].show = device_sysfs_attr[i].show; > + attr[i].store = device_sysfs_attr[i].store; > + } > + edac_ctl->sysfs_attributes = attr; > + > + rc = of_count_phandle_with_args(dn, "cpus", NULL); > + if (rc <= 0) { > + pr_err("Invalid number of phandles in 'cpus'\n"); > + rc = -EINVAL; > + goto out_dev; > + } > + pdata->irq = platform_get_irq(pdev, 0); > + pr_debug("irq is %d\n", pdata->irq); > + > + edac_ctl->poll_msec = poll_msec; > + edac_ctl->edac_check = cortex_arm64_edac_check; > + edac_ctl->dev = dev; > + edac_ctl->mod_name = dev_name(dev); > + edac_ctl->dev_name = dev_name(dev); > + edac_ctl->ctl_name = EDAC_MOD_STR; > + dev_set_drvdata(dev, edac_ctl); > + > + rc = edac_device_add_device(edac_ctl); > + if (rc) > + goto out_dev; > + > + pdata->mem = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL); > + if (!pdata->mem) > + goto out_mem; > + > + if (pdata->irq) { > + get_online_cpus(); > + for_each_cpu_and(cpu, cpu_online_mask, &compat_mask) { > + smp_call_function_single(cpu, > + a53_allow_l1l2_err_irq_clr, > + NULL, > + 1); How do you know this is only called on the A53s? You added all the CPUs to compat_mask. It may be worth having separate probe calls for A53 and A57. Thanks, James > + if (per_cpu(l2ectlr_en, cpu)) { > + pr_err("Failed to enable interrupt clearing (%ld)\n", > + per_cpu(l2ectlr_en, cpu)); > + rc = -EACCES; > + break; > + } > + } > + put_online_cpus(); > + > + if (!rc) { > + rc = devm_request_irq(dev, pdata->irq, cortex_edac_isr, > + 0, "cortex_edac error", edac_ctl); > + if (rc < 0) { > + pr_err("%s: Unable to request irq %d for cortex edac error\n", > + __func__, pdata->irq); > + goto out_irq; > + } > + } > + } > + > + return 0; > + > +out_mem: > +out_irq: > + edac_device_del_device(edac_ctl->dev); > + > +out_dev: > + edac_device_free_ctl_info(edac_ctl); > + > + return rc; > +} > + > +static int cortex_arm64_edac_remove(struct platform_device *pdev) > +{ > + struct edac_device_ctl_info *edac_ctl = dev_get_drvdata(&pdev->dev); > + > + edac_device_del_device(edac_ctl->dev); > + edac_device_free_ctl_info(edac_ctl); > + > + return 0; > +} > + > +static const struct of_device_id cortex_arm64_edac_of_match[] = { > + { .compatible = "arm,cortex-a57-edac" }, > + { .compatible = "arm,cortex-a53-edac" }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, cortex_arm64_edac_of_match); > + > +static struct platform_driver cortex_arm64_edac_driver = { > + .probe = cortex_arm64_edac_probe, > + .remove = cortex_arm64_edac_remove, > + .driver = { > + .name = EDAC_MOD_STR, > + .of_match_table = cortex_arm64_edac_of_match, > + }, > +}; > +module_platform_driver(cortex_arm64_edac_driver); > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("York Sun "); > +MODULE_DESCRIPTION("Cortex A57 and A53 L1 and L2 cache EDAC driver");