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: [2/3] edac: altera: Add support for Stratix10 SDRAM EDAC From: thor.thayer@linux.intel.com Message-Id: <1524594959-5259-3-git-send-email-thor.thayer@linux.intel.com> Date: Tue, 24 Apr 2018 13:35:58 -0500 To: bp@alien8.de, mchehab@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com, dinguyen@kernel.org, catalin.marinas@arm.com, will.deacon@arm.com Cc: thor.thayer@linux.intel.com, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-edac@vger.kernel.org List-ID: RnJvbTogVGhvciBUaGF5ZXIgPHRob3IudGhheWVyQGxpbnV4LmludGVsLmNvbT4KCkFkZCBzdXBw b3J0IGZvciBTRFJBTSBFQ0Mgb24gdGhlIFN0cmF0aXgxMCBwbGF0Zm9ybSB0bwp0aGUgRURBQyBk ZXZpY2UgZHJpdmVyLiBBbHRob3VnaCBTdHJhdGl4MTAgaXMgdmVyeSBzaW1pbGFyCnRvIHRoZSBB cnJpYTEwLCBoeXBlcnZpc29yIHN1cHBvcnQgZm9yIFN0cmF0aXgxMCBTRFJBTSBFQ0MKcmVxdWly ZXMgdGhlIHVzZSBvZiBTTUMgY2FsbHMgdG8gYSBoaWdoZXIgcHJpb3JpdHkKZXhjZXB0aW9uIGxl dmVsIHRvIGhhbmRsZSBzb21lIHJlZ2lzdGVyIHJlYWRzL3dyaXRlcy4KClNpZ25lZC1vZmYtYnk6 IFRob3IgVGhheWVyIDx0aG9yLnRoYXllckBsaW51eC5pbnRlbC5jb20+Ci0tLQogZHJpdmVycy9l ZGFjL0tjb25maWcgICAgICAgfCAgIDIgKy0KIGRyaXZlcnMvZWRhYy9hbHRlcmFfZWRhYy5jIHwg NDU5ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKwogZHJpdmVy cy9lZGFjL2FsdGVyYV9lZGFjLmggfCAxMTQgKysrKysrKysrKysKIDMgZmlsZXMgY2hhbmdlZCwg NTc0IGluc2VydGlvbnMoKyksIDEgZGVsZXRpb24oLSkKCmRpZmYgLS1naXQgYS9kcml2ZXJzL2Vk YWMvS2NvbmZpZyBiL2RyaXZlcnMvZWRhYy9LY29uZmlnCmluZGV4IDNjNDAxNzAwNzY0Ny4uM2M2 NmIwMmIyNDczIDEwMDY0NAotLS0gYS9kcml2ZXJzL2VkYWMvS2NvbmZpZworKysgYi9kcml2ZXJz L2VkYWMvS2NvbmZpZwpAQCAtMzc5LDcgKzM3OSw3IEBAIGNvbmZpZyBFREFDX1RIVU5ERVJYCiAK IGNvbmZpZyBFREFDX0FMVEVSQQogCWJvb2wgIkFsdGVyYSBTT0NGUEdBIEVDQyIKLQlkZXBlbmRz IG9uIEVEQUM9eSAmJiBBUkNIX1NPQ0ZQR0EKKwlkZXBlbmRzIG9uIEVEQUM9eSAmJiAoQVJDSF9T T0NGUEdBIHx8IEFSTTY0KQogCWhlbHAKIAkgIFN1cHBvcnQgZm9yIGVycm9yIGRldGVjdGlvbiBh bmQgY29ycmVjdGlvbiBvbiB0aGUKIAkgIEFsdGVyYSBTT0NzLiBUaGlzIG11c3QgYmUgc2VsZWN0 ZWQgZm9yIFNEUkFNIEVDQy4KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZWRhYy9hbHRlcmFfZWRhYy5j IGIvZHJpdmVycy9lZGFjL2FsdGVyYV9lZGFjLmMKaW5kZXggMTFkNjQxOTc4OGMyLi43ZWQ4ODUz Nzk3MTkgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvZWRhYy9hbHRlcmFfZWRhYy5jCisrKyBiL2RyaXZl cnMvZWRhYy9hbHRlcmFfZWRhYy5jCkBAIC0xLDQgKzEsNSBAQAogLyoKKyAqICBDb3B5cmlnaHQg KEMpIDIwMTctMjAxOCwgSW50ZWwgQ29ycG9yYXRpb24KICAqICBDb3B5cmlnaHQgQWx0ZXJhIENv cnBvcmF0aW9uIChDKSAyMDE0LTIwMTYuIEFsbCByaWdodHMgcmVzZXJ2ZWQuCiAgKiAgQ29weXJp Z2h0IDIwMTEtMjAxMiBDYWx4ZWRhLCBJbmMuCiAgKgpAQCAtODAsNiArODEsMjUgQEAgc3RhdGlj IGNvbnN0IHN0cnVjdCBhbHRyX3NkcmFtX3Bydl9kYXRhIGExMF9kYXRhID0gewogCS51ZV9zZXRf bWFzayAgICAgICAgPSBBMTBfRElBR0lOVF9UREVSUkFfTUFTSywKIH07CiAKK3N0YXRpYyBjb25z dCBzdHJ1Y3QgYWx0cl9zZHJhbV9wcnZfZGF0YSBzMTBfZGF0YSA9IHsKKwkuZWNjX2N0cmxfb2Zm c2V0ICAgID0gUzEwX0VDQ0NUUkwxX09GU1QsCisJLmVjY19jdGxfZW5fbWFzayAgICA9IEExMF9F Q0NDVFJMMV9FQ0NfRU4sCisJLmVjY19zdGF0X29mZnNldCAgICA9IFMxMF9JTlRTVEFUX09GU1Qs CisJLmVjY19zdGF0X2NlX21hc2sgICA9IEExMF9JTlRTVEFUX1NCRUVSUiwKKwkuZWNjX3N0YXRf dWVfbWFzayAgID0gQTEwX0lOVFNUQVRfREJFRVJSLAorCS5lY2Nfc2FkZHJfb2Zmc2V0ICAgPSBT MTBfU0VSUkFERFJfT0ZTVCwKKwkuZWNjX2RhZGRyX29mZnNldCAgID0gUzEwX0RFUlJBRERSX09G U1QsCisJLmVjY19pcnFfZW5fb2Zmc2V0ICA9IFMxMF9FUlJJTlRFTl9PRlNULAorCS5lY2NfaXJx X2VuX21hc2sgICAgPSBBMTBfRUNDX0lSUV9FTl9NQVNLLAorCS5lY2NfaXJxX2Nscl9vZmZzZXQg PSBTMTBfSU5UU1RBVF9PRlNULAorCS5lY2NfaXJxX2Nscl9tYXNrICAgPSAoQTEwX0lOVFNUQVRf U0JFRVJSIHwgQTEwX0lOVFNUQVRfREJFRVJSKSwKKwkuZWNjX2NudF9yc3Rfb2Zmc2V0ID0gUzEw X0VDQ0NUUkwxX09GU1QsCisJLmVjY19jbnRfcnN0X21hc2sgICA9IEExMF9FQ0NfQ05UX1JFU0VU X01BU0ssCisJLmNlX3VlX3RyZ3Jfb2Zmc2V0ICA9IFMxMF9ESUFHSU5UVEVTVF9PRlNULAorCS5j ZV9zZXRfbWFzayAgICAgICAgPSBBMTBfRElBR0lOVF9UU0VSUkFfTUFTSywKKwkudWVfc2V0X21h c2sgICAgICAgID0gQTEwX0RJQUdJTlRfVERFUlJBX01BU0ssCit9OworCiAvKioqKioqKioqKioq KioqKioqKioqKiogRURBQyBNZW1vcnkgQ29udHJvbGxlciBGdW5jdGlvbnMgKioqKioqKioqKioq KioqKi8KIAogLyogVGhlIFNEUkFNIGNvbnRyb2xsZXIgdXNlcyB0aGUgRURBQyBNZW1vcnkgQ29u dHJvbGxlciBmcmFtZXdvcmsuICAgICAgICovCkBAIC0yMzEsNiArMjUxLDcgQEAgc3RhdGljIHVu c2lnbmVkIGxvbmcgZ2V0X3RvdGFsX21lbSh2b2lkKQogc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9k ZXZpY2VfaWQgYWx0cl9zZHJhbV9jdHJsX29mX21hdGNoW10gPSB7CiAJeyAuY29tcGF0aWJsZSA9 ICJhbHRyLHNkcmFtLWVkYWMiLCAuZGF0YSA9ICZjNV9kYXRhfSwKIAl7IC5jb21wYXRpYmxlID0g ImFsdHIsc2RyYW0tZWRhYy1hMTAiLCAuZGF0YSA9ICZhMTBfZGF0YX0sCisJeyAuY29tcGF0aWJs ZSA9ICJhbHRyLHNkcmFtLWVkYWMtczEwIiwgLmRhdGEgPSAmczEwX2RhdGF9LAogCXt9LAogfTsK IE1PRFVMRV9ERVZJQ0VfVEFCTEUob2YsIGFsdHJfc2RyYW1fY3RybF9vZl9tYXRjaCk7CkBAIC00 NzcsNiArNDk4LDI5MiBAQCBzdGF0aWMgaW50IGFsdHJfc2RyYW1fcmVtb3ZlKHN0cnVjdCBwbGF0 Zm9ybV9kZXZpY2UgKnBkZXYpCiAJcmV0dXJuIDA7CiB9CiAKKy8qKioqKioqKioqKioqKioqIFN0 cmF0aXggMTAgRURBQyBNZW1vcnkgQ29udHJvbGxlciBGdW5jdGlvbnMgKioqKioqKioqKioqLwor CisvKioKKyAqIHMxMF9wcm90ZWN0ZWRfcmVnX3dyaXRlCisgKiBXcml0ZSB0byBhIHByb3RlY3Rl ZCBTTUMgcmVnaXN0ZXIuCisgKiBAY29udGV4dDogTm90IHVzZWQuCisgKiBAcmVnOiBBZGRyZXNz IG9mIHJlZ2lzdGVyCisgKiBAdmFsdWU6IFZhbHVlIHRvIHdyaXRlCisgKiBSZXR1cm46IElOVEVM X1NJUF9TTUNfU1RBVFVTX09LICgwKSBvbiBzdWNjZXNzCisgKgkgICBJTlRFTF9TSVBfU01DX1JF R19FUlJPUiBvbiBlcnJvcgorICoJICAgSU5URUxfU0lQX1NNQ19SRVRVUk5fVU5LTk9XTl9GVU5D VElPTiBpZiBub3Qgc3VwcG9ydGVkCisgKi8KK3N0YXRpYyBpbnQgczEwX3Byb3RlY3RlZF9yZWdf d3JpdGUodm9pZCAqY29udGV4dCwgdW5zaWduZWQgaW50IHJlZywKKwkJCQkgICB1bnNpZ25lZCBp bnQgdmFsKQoreworCXN0cnVjdCBhcm1fc21jY2NfcmVzIHJlc3VsdDsKKworCWFybV9zbWNjY19z bWMoSU5URUxfU0lQX1NNQ19SRUdfV1JJVEUsIHJlZywgdmFsLCAwLCAwLAorCQkgICAgICAwLCAw LCAwLCAmcmVzdWx0KTsKKworCXJldHVybiAoaW50KXJlc3VsdC5hMDsKK30KKworLyoqCisgKiBz MTBfcHJvdGVjdGVkX3JlZ19yZWFkCisgKiBSZWFkIHRoZSBzdGF0dXMgb2YgYSBwcm90ZWN0ZWQg U01DIHJlZ2lzdGVyCisgKiBAY29udGV4dDogTm90IHVzZWQuCisgKiBAcmVnOiBBZGRyZXNzIG9m IHJlZ2lzdGVyCisgKiBAdmFsdWU6IFZhbHVlIHJlYWQuCisgKiBSZXR1cm46IElOVEVMX1NJUF9T TUNfU1RBVFVTX09LICgwKSBvbiBzdWNjZXNzCisgKgkgICBJTlRFTF9TSVBfU01DX1JFR19FUlJP UiBvbiBlcnJvcgorICoJICAgSU5URUxfU0lQX1NNQ19SRVRVUk5fVU5LTk9XTl9GVU5DVElPTiBp ZiBub3Qgc3VwcG9ydGVkCisgKi8KK3N0YXRpYyBpbnQgczEwX3Byb3RlY3RlZF9yZWdfcmVhZCh2 b2lkICpjb250ZXh0LCB1bnNpZ25lZCBpbnQgcmVnLAorCQkJCSAgdW5zaWduZWQgaW50ICp2YWwp Cit7CisJc3RydWN0IGFybV9zbWNjY19yZXMgcmVzdWx0OworCisJYXJtX3NtY2NjX3NtYyhJTlRF TF9TSVBfU01DX1JFR19SRUFELCByZWcsIDAsIDAsIDAsCisJCSAgICAgIDAsIDAsIDAsICZyZXN1 bHQpOworCisJKnZhbCA9ICh1bnNpZ25lZCBpbnQpcmVzdWx0LmExOworCisJcmV0dXJuIChpbnQp cmVzdWx0LmEwOworfQorCitzdGF0aWMgYm9vbCBzMTBfc2RyYW1fd3JpdGVhYmxlX3JlZyhzdHJ1 Y3QgZGV2aWNlICpkZXYsIHVuc2lnbmVkIGludCByZWcpCit7CisJc3dpdGNoIChyZWcpIHsKKwlj YXNlIFMxMF9FQ0NDVFJMMV9PRlNUOgorCWNhc2UgUzEwX0VSUklOVEVOX09GU1Q6CisJY2FzZSBT MTBfSU5UTU9ERV9PRlNUOgorCWNhc2UgUzEwX0lOVFNUQVRfT0ZTVDoKKwljYXNlIFMxMF9ESUFH SU5UVEVTVF9PRlNUOgorCWNhc2UgUzEwX1NZU01HUl9FQ0NfSU5UTUFTS19WQUxfT0ZTVDoKKwlj YXNlIFMxMF9TWVNNR1JfRUNDX0lOVE1BU0tfU0VUX09GU1Q6CisJY2FzZSBTMTBfU1lTTUdSX0VD Q19JTlRNQVNLX0NMUl9PRlNUOgorCQlyZXR1cm4gdHJ1ZTsKKwl9CisJcmV0dXJuIGZhbHNlOwor fQorCitzdGF0aWMgYm9vbCBzMTBfc2RyYW1fcmVhZGFibGVfcmVnKHN0cnVjdCBkZXZpY2UgKmRl diwgdW5zaWduZWQgaW50IHJlZykKK3sKKwlzd2l0Y2ggKHJlZykgeworCWNhc2UgUzEwX0VDQ0NU UkwxX09GU1Q6CisJY2FzZSBTMTBfRVJSSU5URU5fT0ZTVDoKKwljYXNlIFMxMF9JTlRNT0RFX09G U1Q6CisJY2FzZSBTMTBfSU5UU1RBVF9PRlNUOgorCWNhc2UgUzEwX0RFUlJBRERSX09GU1Q6CisJ Y2FzZSBTMTBfU0VSUkFERFJfT0ZTVDoKKwljYXNlIFMxMF9ESUFHSU5UVEVTVF9PRlNUOgorCWNh c2UgUzEwX1NZU01HUl9FQ0NfSU5UTUFTS19WQUxfT0ZTVDoKKwljYXNlIFMxMF9TWVNNR1JfRUND X0lOVE1BU0tfU0VUX09GU1Q6CisJY2FzZSBTMTBfU1lTTUdSX0VDQ19JTlRNQVNLX0NMUl9PRlNU OgorCWNhc2UgUzEwX1NZU01HUl9FQ0NfSU5UU1RBVF9TRVJSX09GU1Q6CisJY2FzZSBTMTBfU1lT TUdSX0VDQ19JTlRTVEFUX0RFUlJfT0ZTVDoKKwkJcmV0dXJuIHRydWU7CisJfQorCXJldHVybiBm YWxzZTsKK30KKworc3RhdGljIGJvb2wgczEwX3NkcmFtX3ZvbGF0aWxlX3JlZyhzdHJ1Y3QgZGV2 aWNlICpkZXYsIHVuc2lnbmVkIGludCByZWcpCit7CisJc3dpdGNoIChyZWcpIHsKKwljYXNlIFMx MF9FQ0NDVFJMMV9PRlNUOgorCWNhc2UgUzEwX0VSUklOVEVOX09GU1Q6CisJY2FzZSBTMTBfSU5U TU9ERV9PRlNUOgorCWNhc2UgUzEwX0lOVFNUQVRfT0ZTVDoKKwljYXNlIFMxMF9ERVJSQUREUl9P RlNUOgorCWNhc2UgUzEwX1NFUlJBRERSX09GU1Q6CisJY2FzZSBTMTBfRElBR0lOVFRFU1RfT0ZT VDoKKwljYXNlIFMxMF9TWVNNR1JfRUNDX0lOVE1BU0tfVkFMX09GU1Q6CisJY2FzZSBTMTBfU1lT TUdSX0VDQ19JTlRNQVNLX1NFVF9PRlNUOgorCWNhc2UgUzEwX1NZU01HUl9FQ0NfSU5UTUFTS19D TFJfT0ZTVDoKKwljYXNlIFMxMF9TWVNNR1JfRUNDX0lOVFNUQVRfU0VSUl9PRlNUOgorCWNhc2Ug UzEwX1NZU01HUl9FQ0NfSU5UU1RBVF9ERVJSX09GU1Q6CisJCXJldHVybiB0cnVlOworCX0KKwly ZXR1cm4gZmFsc2U7Cit9CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3QgcmVnbWFwX2NvbmZpZyBzMTBf c2RyYW1fcmVnbWFwX2NmZyA9IHsKKwkubmFtZSA9ICJzMTBfZGRyIiwKKwkucmVnX2JpdHMgPSAz MiwKKwkucmVnX3N0cmlkZSA9IDQsCisJLnZhbF9iaXRzID0gMzIsCisJLm1heF9yZWdpc3RlciA9 IDB4ZmZmZmZmZmYsCisJLndyaXRlYWJsZV9yZWcgPSBzMTBfc2RyYW1fd3JpdGVhYmxlX3JlZywK KwkucmVhZGFibGVfcmVnID0gczEwX3NkcmFtX3JlYWRhYmxlX3JlZywKKwkudm9sYXRpbGVfcmVn ID0gczEwX3NkcmFtX3ZvbGF0aWxlX3JlZywKKwkucmVnX3JlYWQgPSBzMTBfcHJvdGVjdGVkX3Jl Z19yZWFkLAorCS5yZWdfd3JpdGUgPSBzMTBfcHJvdGVjdGVkX3JlZ193cml0ZSwKKwkudXNlX3Np bmdsZV9ydyA9IHRydWUsCit9OworCitzdGF0aWMgaW50IGFsdHJfczEwX3NkcmFtX3Byb2JlKHN0 cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpCit7CisJY29uc3Qgc3RydWN0IG9mX2RldmljZV9p ZCAqaWQ7CisJc3RydWN0IGVkYWNfbWNfbGF5ZXIgbGF5ZXJzWzJdOworCXN0cnVjdCBtZW1fY3Rs X2luZm8gKm1jaTsKKwlzdHJ1Y3QgYWx0cl9zZHJhbV9tY19kYXRhICpkcnZkYXRhOworCWNvbnN0 IHN0cnVjdCBhbHRyX3NkcmFtX3Bydl9kYXRhICpwcml2OworCXN0cnVjdCByZWdtYXAgKnJlZ21h cDsKKwlzdHJ1Y3QgZGltbV9pbmZvICpkaW1tOworCXUzMiByZWFkX3JlZzsKKwlzdHJ1Y3QgcmVz b3VyY2UgKnJlczsKKwlpbnQgaXJxLCByZXQgPSAwOworCXVuc2lnbmVkIGxvbmcgbWVtX3NpemU7 CisJdm9pZCBfX2lvbWVtICpyZWdfYmFzZTsKKworCWlkID0gb2ZfbWF0Y2hfZGV2aWNlKGFsdHJf c2RyYW1fY3RybF9vZl9tYXRjaCwgJnBkZXYtPmRldik7CisJaWYgKCFpZCkKKwkJcmV0dXJuIC1F Tk9ERVY7CisKKwkvKiBHcmFiIHNwZWNpZmljIG9mZnNldHMgYW5kIG1hc2tzIGZvciBTdHJhdGl4 MTAgKi8KKwlwcml2ID0gb2ZfbWF0Y2hfbm9kZShhbHRyX3NkcmFtX2N0cmxfb2ZfbWF0Y2gsCisJ CQkgICAgIHBkZXYtPmRldi5vZl9ub2RlKS0+ZGF0YTsKKwkvKiBHcmFiIHRoZSByZWdpc3RlciBy YW5nZSBmcm9tIHRoZSBzZHIgY29udHJvbGxlciBpbiBkZXZpY2UgdHJlZSAqLworCXJlcyA9IHBs YXRmb3JtX2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7CisJcmVnX2Jhc2Ug PSBkZXZtX2lvcmVtYXBfcmVzb3VyY2UoJnBkZXYtPmRldiwgcmVzKTsKKwlpZiAoSVNfRVJSKHJl Z19iYXNlKSkKKwkJcmV0dXJuIFBUUl9FUlIocmVnX2Jhc2UpOworCisJcmVnbWFwID0gZGV2bV9y ZWdtYXBfaW5pdCgmcGRldi0+ZGV2LCBOVUxMLCAodm9pZCAqKXByaXYsCisJCQkJICAmczEwX3Nk cmFtX3JlZ21hcF9jZmcpOworCWlmIChJU19FUlIocmVnbWFwKSkKKwkJcmV0dXJuIFBUUl9FUlIo cmVnbWFwKTsKKworCS8qIFZhbGlkYXRlIHRoZSBTRFJBTSBjb250cm9sbGVyIGhhcyBFQ0MgZW5h YmxlZCAqLworCWlmIChyZWdtYXBfcmVhZChyZWdtYXAsIHByaXYtPmVjY19jdHJsX29mZnNldCwg JnJlYWRfcmVnKSB8fAorCSAgICAoKHJlYWRfcmVnICYgcHJpdi0+ZWNjX2N0bF9lbl9tYXNrKSAh PSBwcml2LT5lY2NfY3RsX2VuX21hc2spKSB7CisJCWVkYWNfcHJpbnRrKEtFUk5fRVJSLCBFREFD X01DLAorCQkJICAgICJObyBFQ0MvRUNDIGRpc2FibGVkIFsweCUwOFhdXG4iLCByZWFkX3JlZyk7 CisJCXJldHVybiAtRU5PREVWOworCX0KKworCS8qIEdyYWIgbWVtb3J5IHNpemUgZnJvbSBkZXZp Y2UgdHJlZS4gKi8KKwltZW1fc2l6ZSA9IGdldF90b3RhbF9tZW0oKTsKKwlpZiAoIW1lbV9zaXpl KSB7CisJCWVkYWNfcHJpbnRrKEtFUk5fRVJSLCBFREFDX01DLCAiVW5hYmxlIHRvIGNhbGN1bGF0 ZSBtZW1vcnkgc2l6ZVxuIik7CisJCXJldHVybiAtRU5PREVWOworCX0KKworCS8qIEVuc3VyZSB0 aGUgU0RSQU0gSW50ZXJydXB0IGlzIGRpc2FibGVkICovCisJaWYgKHJlZ21hcF91cGRhdGVfYml0 cyhyZWdtYXAsIHByaXYtPmVjY19pcnFfZW5fb2Zmc2V0LAorCQkJICAgICAgIHByaXYtPmVjY19p cnFfZW5fbWFzaywgMCkpIHsKKwkJZWRhY19wcmludGsoS0VSTl9FUlIsIEVEQUNfTUMsCisJCQkg ICAgIkVycm9yIGRpc2FibGluZyBTRFJBTSBFQ0MgSVJRXG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7 CisJfQorCisJLyogVG9nZ2xlIHRvIGNsZWFyIHRoZSBTRFJBTSBFcnJvciBjb3VudCAqLworCWlm IChyZWdtYXBfdXBkYXRlX2JpdHMocmVnbWFwLCBwcml2LT5lY2NfY250X3JzdF9vZmZzZXQsCisJ CQkgICAgICAgcHJpdi0+ZWNjX2NudF9yc3RfbWFzaywKKwkJCSAgICAgICBwcml2LT5lY2NfY250 X3JzdF9tYXNrKSkgeworCQllZGFjX3ByaW50ayhLRVJOX0VSUiwgRURBQ19NQywKKwkJCSAgICAi RXJyb3IgY2xlYXJpbmcgU0RSQU0gRUNDIGNvdW50XG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJ fQorCisJaWYgKHJlZ21hcF91cGRhdGVfYml0cyhyZWdtYXAsIHByaXYtPmVjY19jbnRfcnN0X29m ZnNldCwKKwkJCSAgICAgICBwcml2LT5lY2NfY250X3JzdF9tYXNrLCAwKSkgeworCQllZGFjX3By aW50ayhLRVJOX0VSUiwgRURBQ19NQywKKwkJCSAgICAiRXJyb3IgY2xlYXJpbmcgU0RSQU0gRUND IGNvdW50XG4iKTsKKwkJcmV0dXJuIC1FTk9ERVY7CisJfQorCisJaXJxID0gcGxhdGZvcm1fZ2V0 X2lycShwZGV2LCAwKTsKKwlpZiAoaXJxIDwgMCkgeworCQllZGFjX3ByaW50ayhLRVJOX0VSUiwg RURBQ19NQywKKwkJCSAgICAiTm8gaXJxICVkIGluIERUXG4iLCBpcnEpOworCQlyZXR1cm4gLUVO T0RFVjsKKwl9CisKKwlsYXllcnNbMF0udHlwZSA9IEVEQUNfTUNfTEFZRVJfQ0hJUF9TRUxFQ1Q7 CisJbGF5ZXJzWzBdLnNpemUgPSAxOworCWxheWVyc1swXS5pc192aXJ0X2Nzcm93ID0gdHJ1ZTsK KwlsYXllcnNbMV0udHlwZSA9IEVEQUNfTUNfTEFZRVJfQ0hBTk5FTDsKKwlsYXllcnNbMV0uc2l6 ZSA9IDE7CisJbGF5ZXJzWzFdLmlzX3ZpcnRfY3Nyb3cgPSBmYWxzZTsKKwltY2kgPSBlZGFjX21j X2FsbG9jKDAsIEFSUkFZX1NJWkUobGF5ZXJzKSwgbGF5ZXJzLAorCQkJICAgIHNpemVvZihzdHJ1 Y3QgYWx0cl9zZHJhbV9tY19kYXRhKSk7CisJaWYgKCFtY2kpCisJCXJldHVybiAtRU5PTUVNOwor CisJbWNpLT5wZGV2ID0gJnBkZXYtPmRldjsKKwlkcnZkYXRhID0gbWNpLT5wdnRfaW5mbzsKKwlk cnZkYXRhLT5tY192YmFzZSA9IHJlZ21hcDsKKwlkcnZkYXRhLT5kYXRhID0gcHJpdjsKKwlwbGF0 Zm9ybV9zZXRfZHJ2ZGF0YShwZGV2LCBtY2kpOworCisJaWYgKCFkZXZyZXNfb3Blbl9ncm91cCgm cGRldi0+ZGV2LCBOVUxMLCBHRlBfS0VSTkVMKSkgeworCQllZGFjX3ByaW50ayhLRVJOX0VSUiwg RURBQ19NQywKKwkJCSAgICAiVW5hYmxlIHRvIGdldCBtYW5hZ2VkIGRldmljZSByZXNvdXJjZVxu Iik7CisJCXJldCA9IC1FTk9NRU07CisJCWdvdG8gZnJlZTsKKwl9CisKKwltY2ktPm10eXBlX2Nh cCA9IE1FTV9GTEFHX0REUjM7CisJbWNpLT5lZGFjX2N0bF9jYXAgPSBFREFDX0ZMQUdfTk9ORSB8 IEVEQUNfRkxBR19TRUNERUQ7CisJbWNpLT5lZGFjX2NhcCA9IEVEQUNfRkxBR19TRUNERUQ7CisJ bWNpLT5tb2RfbmFtZSA9IEVEQUNfTU9EX1NUUjsKKwltY2ktPmN0bF9uYW1lID0gZGV2X25hbWUo JnBkZXYtPmRldik7CisJbWNpLT5zY3J1Yl9tb2RlID0gU0NSVUJfU1dfU1JDOworCW1jaS0+ZGV2 X25hbWUgPSBkZXZfbmFtZSgmcGRldi0+ZGV2KTsKKworCWRpbW0gPSAqbWNpLT5kaW1tczsKKwlk aW1tLT5ucl9wYWdlcyA9ICgobWVtX3NpemUgLSAxKSA+PiBQQUdFX1NISUZUKSArIDE7CisJZGlt bS0+Z3JhaW4gPSA4OworCWRpbW0tPmR0eXBlID0gREVWX1g4OworCWRpbW0tPm10eXBlID0gTUVN X0REUjM7CisJZGltbS0+ZWRhY19tb2RlID0gRURBQ19TRUNERUQ7CisKKwlyZXQgPSBlZGFjX21j X2FkZF9tYyhtY2kpOworCWlmIChyZXQgPCAwKQorCQlnb3RvIGVycjsKKworCXJldCA9IGRldm1f cmVxdWVzdF9pcnEoJnBkZXYtPmRldiwgaXJxLCBhbHRyX3NkcmFtX21jX2Vycl9oYW5kbGVyLAor CQkJICAgICAgIElSUUZfU0hBUkVELCBkZXZfbmFtZSgmcGRldi0+ZGV2KSwgbWNpKTsKKwlpZiAo cmV0IDwgMCkgeworCQllZGFjX21jX3ByaW50ayhtY2ksIEtFUk5fRVJSLAorCQkJICAgICAgICJV bmFibGUgdG8gcmVxdWVzdCBpcnEgJWRcbiIsIGlycSk7CisJCXJldCA9IC1FTk9ERVY7CisJCWdv dG8gZXJyMjsKKwl9CisKKwlpZiAocmVnbWFwX3VwZGF0ZV9iaXRzKGRydmRhdGEtPm1jX3ZiYXNl LCBwcml2LT5lY2NfaXJxX2VuX29mZnNldCwKKwkJCSAgICAgICBwcml2LT5lY2NfaXJxX2VuX21h c2ssIHByaXYtPmVjY19pcnFfZW5fbWFzaykpIHsKKwkJZWRhY19tY19wcmludGsobWNpLCBLRVJO X0VSUiwKKwkJCSAgICAgICAiRXJyb3IgZW5hYmxpbmcgU0RSQU0gRUNDIElSUVxuIik7CisJCXJl dCA9IC1FTk9ERVY7CisJCWdvdG8gZXJyMjsKKwl9CisKKwlhbHRyX3Nkcl9tY19jcmVhdGVfZGVi dWdmc19ub2RlcyhtY2kpOworCisJZGV2cmVzX2Nsb3NlX2dyb3VwKCZwZGV2LT5kZXYsIE5VTEwp OworCisJcmV0dXJuIDA7CisKK2VycjI6CisJZWRhY19tY19kZWxfbWMoJnBkZXYtPmRldik7Citl cnI6CisJZGV2cmVzX3JlbGVhc2VfZ3JvdXAoJnBkZXYtPmRldiwgTlVMTCk7CitmcmVlOgorCWVk YWNfbWNfZnJlZShtY2kpOworCWVkYWNfcHJpbnRrKEtFUk5fRVJSLCBFREFDX01DLAorCQkgICAg IkVEQUMgUHJvYmUgRmFpbGVkOyBFcnJvciAlZFxuIiwgcmV0KTsKKworCXJldHVybiByZXQ7Cit9 CisKK3N0YXRpYyBpbnQgYWx0cl9zMTBfc2RyYW1fcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UgKnBkZXYpCit7CisJc3RydWN0IG1lbV9jdGxfaW5mbyAqbWNpID0gcGxhdGZvcm1fZ2V0X2Ry dmRhdGEocGRldik7CisKKwllZGFjX21jX2RlbF9tYygmcGRldi0+ZGV2KTsKKwllZGFjX21jX2Zy ZWUobWNpKTsKKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0YShwZGV2LCBOVUxMKTsKKworCXJldHVybiAw OworfQorCisvKioqKioqKioqKioqKiogPC9TdHJhdGl4MTAgRURBQyBNZW1vcnkgQ29udHJvbGxl ciBGdW5jdGlvbnM+ICoqKioqKioqKioqLworCiAvKgogICogSWYgeW91IHdhbnQgdG8gc3VzcGVu ZCwgbmVlZCB0byBkaXNhYmxlIEVEQUMgYnkgcmVtb3ZpbmcgaXQKICAqIGZyb20gdGhlIGRldmlj ZSB0cmVlIG9yIGRlZmNvbmZpZy4KQEAgLTUwOCw2ICs4MTUsMjAgQEAgc3RhdGljIHN0cnVjdCBw bGF0Zm9ybV9kcml2ZXIgYWx0cl9zZHJhbV9lZGFjX2RyaXZlciA9IHsKIAogbW9kdWxlX3BsYXRm b3JtX2RyaXZlcihhbHRyX3NkcmFtX2VkYWNfZHJpdmVyKTsKIAorc3RhdGljIHN0cnVjdCBwbGF0 Zm9ybV9kcml2ZXIgYWx0cl9zMTBfc2RyYW1fZWRhY19kcml2ZXIgPSB7CisJLnByb2JlID0gYWx0 cl9zMTBfc2RyYW1fcHJvYmUsCisJLnJlbW92ZSA9IGFsdHJfczEwX3NkcmFtX3JlbW92ZSwKKwku ZHJpdmVyID0geworCQkubmFtZSA9ICJhbHRyX3MxMF9zZHJhbV9lZGFjIiwKKyNpZmRlZiBDT05G SUdfUE0KKwkJLnBtID0gJmFsdHJfc2RyYW1fcG1fb3BzLAorI2VuZGlmCisJCS5vZl9tYXRjaF90 YWJsZSA9IGFsdHJfc2RyYW1fY3RybF9vZl9tYXRjaCwKKwl9LAorfTsKKworbW9kdWxlX3BsYXRm b3JtX2RyaXZlcihhbHRyX3MxMF9zZHJhbV9lZGFjX2RyaXZlcik7CisKIC8qKioqKioqKioqKioq KioqKioqKioqKioqIEVEQUMgUGFyZW50IFByb2JlICoqKioqKioqKioqKioqKioqKioqKioqKiov CiAKIHN0YXRpYyBjb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIGFsdHJfZWRhY19kZXZpY2Vfb2Zf bWF0Y2hbXTsKQEAgLTE5MjUsNiArMjI0NiwxNDQgQEAgc3RhdGljIHN0cnVjdCBwbGF0Zm9ybV9k cml2ZXIgYWx0cl9lZGFjX2ExMF9kcml2ZXIgPSB7CiB9OwogbW9kdWxlX3BsYXRmb3JtX2RyaXZl cihhbHRyX2VkYWNfYTEwX2RyaXZlcik7CiAKKy8qKioqKioqKioqKioqKiBTdHJhdGl4IDEwIEVE QUMgRGV2aWNlIENvbnRyb2xsZXIgRnVuY3Rpb25zPiAqKioqKioqKioqKiovCisKK3N0YXRpYyB2 b2lkIGFsdHJfZWRhY19zMTBfaXJxX2hhbmRsZXIoc3RydWN0IGlycV9kZXNjICpkZXNjKQorewor CWludCBkYmVyciwgYml0LCBzbV9vZmZzZXQsIGlycV9zdGF0dXM7CisJdW5zaWduZWQgbG9uZyBm bGFnczsKKwlzdHJ1Y3QgYWx0cl9zdHJhdGl4MTBfZWRhYyAqZWRhYyA9IGlycV9kZXNjX2dldF9o YW5kbGVyX2RhdGEoZGVzYyk7CisJc3RydWN0IGlycV9jaGlwICpjaGlwID0gaXJxX2Rlc2NfZ2V0 X2NoaXAoZGVzYyk7CisJaW50IGlycSA9IGlycV9kZXNjX2dldF9pcnEoZGVzYyk7CisKKwlzcGlu X2xvY2tfaXJxc2F2ZSgmZWRhYy0+bG9jaywgZmxhZ3MpOworCWRiZXJyID0gKGlycSA9PSBlZGFj LT5kYl9pcnEpID8gMSA6IDA7CisJc21fb2Zmc2V0ID0gZGJlcnIgPyBTMTBfU1lTTUdSX0VDQ19J TlRTVEFUX0RFUlJfT0ZTVCA6CisJCQkgICAgUzEwX1NZU01HUl9FQ0NfSU5UU1RBVF9TRVJSX09G U1Q7CisKKwljaGFpbmVkX2lycV9lbnRlcihjaGlwLCBkZXNjKTsKKworCXMxMF9wcm90ZWN0ZWRf cmVnX3JlYWQoTlVMTCwgc21fb2Zmc2V0LCAmaXJxX3N0YXR1cyk7CisKKwlmb3JfZWFjaF9zZXRf Yml0KGJpdCwgKHVuc2lnbmVkIGxvbmcgKikmaXJxX3N0YXR1cywgMzIpIHsKKwkJaXJxID0gaXJx X2xpbmVhcl9yZXZtYXAoZWRhYy0+ZG9tYWluLCBkYmVyciAqIDMyICsgYml0KTsKKwkJaWYgKGly cSkKKwkJCWdlbmVyaWNfaGFuZGxlX2lycShpcnEpOworCX0KKworCWNoYWluZWRfaXJxX2V4aXQo Y2hpcCwgZGVzYyk7CisJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmZWRhYy0+bG9jaywgZmxhZ3Mp OworfQorCitzdGF0aWMgdm9pZCBzMTBfZWNjbWdyX2lycV9tYXNrKHN0cnVjdCBpcnFfZGF0YSAq ZCkKK3sKKwlzdHJ1Y3QgYWx0cl9zdHJhdGl4MTBfZWRhYyAqZWRhYyA9IGlycV9kYXRhX2dldF9p cnFfY2hpcF9kYXRhKGQpOworCisJczEwX3Byb3RlY3RlZF9yZWdfd3JpdGUoZWRhYywgUzEwX1NZ U01HUl9FQ0NfSU5UTUFTS19TRVRfT0ZTVCwKKwkJCQlCSVQoZC0+aHdpcnEpKTsKK30KKworc3Rh dGljIHZvaWQgczEwX2VjY21ncl9pcnFfdW5tYXNrKHN0cnVjdCBpcnFfZGF0YSAqZCkKK3sKKwlz dHJ1Y3QgYWx0cl9zdHJhdGl4MTBfZWRhYyAqZWRhYyA9IGlycV9kYXRhX2dldF9pcnFfY2hpcF9k YXRhKGQpOworCisJczEwX3Byb3RlY3RlZF9yZWdfd3JpdGUoZWRhYywgUzEwX1NZU01HUl9FQ0Nf SU5UTUFTS19DTFJfT0ZTVCwKKwkJCQlCSVQoZC0+aHdpcnEpKTsKK30KKworc3RhdGljIGludCBz MTBfZWNjbWdyX2lycWRvbWFpbl9tYXAoc3RydWN0IGlycV9kb21haW4gKmQsIHVuc2lnbmVkIGlu dCBpcnEsCisJCQkJICAgIGlycV9od19udW1iZXJfdCBod2lycSkKK3sKKwlzdHJ1Y3QgYWx0cl9z dHJhdGl4MTBfZWRhYyAqZWRhYyA9IGQtPmhvc3RfZGF0YTsKKworCWlycV9zZXRfY2hpcF9hbmRf aGFuZGxlcihpcnEsICZlZGFjLT5pcnFfY2hpcCwgaGFuZGxlX3NpbXBsZV9pcnEpOworCWlycV9z ZXRfY2hpcF9kYXRhKGlycSwgZWRhYyk7CisJaXJxX3NldF9ub3Byb2JlKGlycSk7CisKKwlyZXR1 cm4gMDsKK30KKworc3RhdGljIGNvbnN0IHN0cnVjdCBpcnFfZG9tYWluX29wcyBzMTBfZWNjbWdy X2ljX29wcyA9IHsKKwkubWFwID0gczEwX2VjY21ncl9pcnFkb21haW5fbWFwLAorCS54bGF0ZSA9 IGlycV9kb21haW5feGxhdGVfdHdvY2VsbCwKK307CisKK3N0YXRpYyBpbnQgYWx0cl9lZGFjX3Mx MF9wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQoreworCXN0cnVjdCBhbHRyX3N0 cmF0aXgxMF9lZGFjICplZGFjOworCXN0cnVjdCBkZXZpY2Vfbm9kZSAqY2hpbGQ7CisKKwllZGFj ID0gZGV2bV9remFsbG9jKCZwZGV2LT5kZXYsIHNpemVvZigqZWRhYyksIEdGUF9LRVJORUwpOwor CWlmICghZWRhYykKKwkJcmV0dXJuIC1FTk9NRU07CisKKwllZGFjLT5kZXYgPSAmcGRldi0+ZGV2 OworCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIGVkYWMpOworCUlOSVRfTElTVF9IRUFEKCZl ZGFjLT5zMTBfZWNjX2RldmljZXMpOworCXNwaW5fbG9ja19pbml0KCZlZGFjLT5sb2NrKTsKKwor CWVkYWMtPmVjY19tZ3JfbWFwID0gc3lzY29uX3JlZ21hcF9sb29rdXBfYnlfcGhhbmRsZShwZGV2 LT5kZXYub2Zfbm9kZSwKKwkJCQkJCQkiYWx0cixzeXNtZ3Itc3lzY29uIik7CisJaWYgKElTX0VS UihlZGFjLT5lY2NfbWdyX21hcCkpIHsKKwkJZWRhY19wcmludGsoS0VSTl9FUlIsIEVEQUNfREVW SUNFLAorCQkJICAgICJVbmFibGUgdG8gZ2V0IHN5c2NvbiBhbHRyLHN5c21nci1zeXNjb25cbiIp OworCQlyZXR1cm4gUFRSX0VSUihlZGFjLT5lY2NfbWdyX21hcCk7CisJfQorCisJZWRhYy0+aXJx X2NoaXAubmFtZSA9IHBkZXYtPmRldi5vZl9ub2RlLT5uYW1lOworCWVkYWMtPmlycV9jaGlwLmly cV9tYXNrID0gczEwX2VjY21ncl9pcnFfbWFzazsKKwllZGFjLT5pcnFfY2hpcC5pcnFfdW5tYXNr ID0gczEwX2VjY21ncl9pcnFfdW5tYXNrOworCWVkYWMtPmRvbWFpbiA9IGlycV9kb21haW5fYWRk X2xpbmVhcihwZGV2LT5kZXYub2Zfbm9kZSwgNjQsCisJCQkJCSAgICAgJnMxMF9lY2NtZ3JfaWNf b3BzLCBlZGFjKTsKKwlpZiAoIWVkYWMtPmRvbWFpbikgeworCQlkZXZfZXJyKCZwZGV2LT5kZXYs ICJFcnJvciBhZGRpbmcgSVJRIGRvbWFpblxuIik7CisJCXJldHVybiAtRU5PTUVNOworCX0KKwor CWVkYWMtPnNiX2lycSA9IHBsYXRmb3JtX2dldF9pcnEocGRldiwgMCk7CisJaWYgKGVkYWMtPnNi X2lycSA8IDApIHsKKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiTm8gU0JFUlIgSVJRIHJlc291cmNl XG4iKTsKKwkJcmV0dXJuIGVkYWMtPnNiX2lycTsKKwl9CisKKwlpcnFfc2V0X2NoYWluZWRfaGFu ZGxlcl9hbmRfZGF0YShlZGFjLT5zYl9pcnEsCisJCQkJCSBhbHRyX2VkYWNfczEwX2lycV9oYW5k bGVyLAorCQkJCQkgZWRhYyk7CisKKwllZGFjLT5kYl9pcnEgPSBwbGF0Zm9ybV9nZXRfaXJxKHBk ZXYsIDEpOworCWlmIChlZGFjLT5kYl9pcnEgPj0gMCkKKwkJaXJxX3NldF9jaGFpbmVkX2hhbmRs ZXJfYW5kX2RhdGEoZWRhYy0+ZGJfaXJxLAorCQkJCQkJIGFsdHJfZWRhY19zMTBfaXJxX2hhbmRs ZXIsCisJCQkJCQkgZWRhYyk7CisKKwlmb3JfZWFjaF9jaGlsZF9vZl9ub2RlKHBkZXYtPmRldi5v Zl9ub2RlLCBjaGlsZCkgeworCQlpZiAoIW9mX2RldmljZV9pc19hdmFpbGFibGUoY2hpbGQpKQor CQkJY29udGludWU7CisKKwkJaWYgKG9mX2RldmljZV9pc19jb21wYXRpYmxlKGNoaWxkLCAiYWx0 cixzZHJhbS1lZGFjLXMxMCIpKQorCQkJb2ZfcGxhdGZvcm1fcG9wdWxhdGUocGRldi0+ZGV2Lm9m X25vZGUsCisJCQkJCSAgICAgYWx0cl9zZHJhbV9jdHJsX29mX21hdGNoLAorCQkJCQkgICAgIE5V TEwsICZwZGV2LT5kZXYpOworCX0KKworCXJldHVybiAwOworfQorCitzdGF0aWMgY29uc3Qgc3Ry dWN0IG9mX2RldmljZV9pZCBhbHRyX2VkYWNfczEwX29mX21hdGNoW10gPSB7CisJeyAuY29tcGF0 aWJsZSA9ICJhbHRyLHNvY2ZwZ2EtczEwLWVjYy1tYW5hZ2VyIiB9LAorCXt9LAorfTsKK01PRFVM RV9ERVZJQ0VfVEFCTEUob2YsIGFsdHJfZWRhY19zMTBfb2ZfbWF0Y2gpOworCitzdGF0aWMgc3Ry dWN0IHBsYXRmb3JtX2RyaXZlciBhbHRyX2VkYWNfczEwX2RyaXZlciA9IHsKKwkucHJvYmUgPSAg YWx0cl9lZGFjX3MxMF9wcm9iZSwKKwkuZHJpdmVyID0geworCQkubmFtZSA9ICJzb2NmcGdhX3Mx MF9lY2NfbWFuYWdlciIsCisJCS5vZl9tYXRjaF90YWJsZSA9IGFsdHJfZWRhY19zMTBfb2ZfbWF0 Y2gsCisJfSwKK307Cittb2R1bGVfcGxhdGZvcm1fZHJpdmVyKGFsdHJfZWRhY19zMTBfZHJpdmVy KTsKKwogTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwogTU9EVUxFX0FVVEhPUigiVGhvciBUaGF5 ZXIiKTsKIE1PRFVMRV9ERVNDUklQVElPTigiRURBQyBEcml2ZXIgZm9yIEFsdGVyYSBNZW1vcmll cyIpOwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9lZGFjL2FsdGVyYV9lZGFjLmggYi9kcml2ZXJzL2Vk YWMvYWx0ZXJhX2VkYWMuaAppbmRleCBjYmM5NjI5MGY3NDMuLjEwMjQ1MjhkYzY3YSAxMDA2NDQK LS0tIGEvZHJpdmVycy9lZGFjL2FsdGVyYV9lZGFjLmgKKysrIGIvZHJpdmVycy9lZGFjL2FsdGVy YV9lZGFjLmgKQEAgLTE4LDYgKzE4LDcgQEAKICNpZm5kZWYgX0FMVEVSQV9FREFDX0gKICNkZWZp bmUgX0FMVEVSQV9FREFDX0gKIAorI2luY2x1ZGUgPGxpbnV4L2FybS1zbWNjYy5oPgogI2luY2x1 ZGUgPGxpbnV4L2VkYWMuaD4KICNpbmNsdWRlIDxsaW51eC90eXBlcy5oPgogCkBAIC05NCw2ICs5 NSw3IEBACiAvKiBTRFJBTSBDb250cm9sbGVyIEFkZHJlc3MgV2lkdGggUmVnaXN0ZXIgKi8KICNk ZWZpbmUgQ1ZfRFJBTUFERFJXICAgICAgICAgICAgICAgMHhGRkMyNTAyQwogI2RlZmluZSBBMTBf RFJBTUFERFJXICAgICAgICAgICAgICAweEZGQ0ZBMEE4CisjZGVmaW5lIFMxMF9EUkFNQUREUlcg ICAgICAgICAgICAgIDB4RjgwMTEwRTAKIAogLyogU0RSQU0gQ29udHJvbGxlciBBZGRyZXNzIFdp ZHRocyBGaWVsZCBSZWdpc3RlciAqLwogI2RlZmluZSBEUkFNQUREUldfQ09MQklUX01BU0sgICAg ICAweDAwMUYKQEAgLTExNSw2ICsxMTcsNyBAQAogLyogU0RSQU0gQ29udHJvbGxlciBJbnRlcmZh Y2UgRGF0YSBXaWR0aCBSZWdpc3RlciAqLwogI2RlZmluZSBDVl9EUkFNSUZXSURUSCAgICAgICAg ICAgICAweEZGQzI1MDMwCiAjZGVmaW5lIEExMF9EUkFNSUZXSURUSCAgICAgICAgICAgIDB4RkZD RkIwMDgKKyNkZWZpbmUgUzEwX0RSQU1JRldJRFRIICAgICAgICAgICAgMHhGODAxMTAwOAogCiAv KiBTRFJBTSBDb250cm9sbGVyIEludGVyZmFjZSBEYXRhIFdpZHRoIERlZmluZXMgKi8KICNkZWZp bmUgQ1ZfRFJBTUlGV0lEVEhfMTZCX0VDQyAgICAgMjQKQEAgLTE2NCw2ICsxNjcsMzAgQEAKICNk ZWZpbmUgQTEwX0lOVE1BU0tfQ0xSX09GU1QgICAgICAgMHgxMAogI2RlZmluZSBBMTBfRERSMF9J UlFfTUFTSyAgICAgICAgICBCSVQoMTcpCiAKKy8qKioqKioqKioqKioqIFN0cmF0aXgxMCBEZWZp bmVzICoqKioqKioqKioqKioqLworCisvKiBTRFJBTSBDb250cm9sbGVyIEVjY0N0cmwgUmVnaXN0 ZXIgKi8KKyNkZWZpbmUgUzEwX0VDQ0NUUkwxX09GU1QgICAgICAgICAgMHhGODAxMTEwMAorCisv KiBTRFJBTSBDb250cm9sbGVyIERSQU0gSVJRIFJlZ2lzdGVyICovCisjZGVmaW5lIFMxMF9FUlJJ TlRFTl9PRlNUICAgICAgICAgIDB4RjgwMTExMTAKKworLyogU0RSQU0gSW50ZXJydXB0IE1vZGUg UmVnaXN0ZXIgKi8KKyNkZWZpbmUgUzEwX0lOVE1PREVfT0ZTVCAgICAgICAgICAgMHhGODAxMTEx QworCisvKiBTRFJBTSBDb250cm9sbGVyIEVycm9yIFN0YXR1cyBSZWdpc3RlciAqLworI2RlZmlu ZSBTMTBfSU5UU1RBVF9PRlNUICAgICAgICAgICAweEY4MDExMTIwCisKKy8qIFNEUkFNIENvbnRy b2xsZXIgRUNDIEVycm9yIEFkZHJlc3MgUmVnaXN0ZXIgKi8KKyNkZWZpbmUgUzEwX0RFUlJBRERS X09GU1QgICAgICAgICAgMHhGODAxMTEyQworI2RlZmluZSBTMTBfU0VSUkFERFJfT0ZTVCAgICAg ICAgICAweEY4MDExMTMwCisKKy8qIFNEUkFNIENvbnRyb2xsZXIgRUNDIERpYWdub3N0aWMgUmVn aXN0ZXIgKi8KKyNkZWZpbmUgUzEwX0RJQUdJTlRURVNUX09GU1QgICAgICAgMHhGODAxMTEyNAor CisvKiBTRFJBTSBTaW5nbGUgQml0IEVycm9yIENvdW50IENvbXBhcmUgU2V0IFJlZ2lzdGVyICov CisjZGVmaW5lIFMxMF9TRVJSQ05UUkVHX09GU1QgICAgICAgIDB4RjgwMTExM0MKKwogc3RydWN0 IGFsdHJfc2RyYW1fcHJ2X2RhdGEgewogCWludCBlY2NfY3RybF9vZmZzZXQ7CiAJaW50IGVjY19j dGxfZW5fbWFzazsKQEAgLTI5Niw2ICszMjMsMTYgQEAgc3RydWN0IGFsdHJfc2RyYW1fbWNfZGF0 YSB7CiAvKiBBMTAgRUNDIENvbnRyb2xsZXIgbWVtb3J5IGluaXRpYWxpemF0aW9uIHRpbWVvdXQg Ki8KICNkZWZpbmUgQUxUUl9BMTBfRUNDX0lOSVRfV0FUQ0hET0dfMTBVUyAgICAgIDEwMDAwCiAK Ky8qKioqKioqKioqKioqIFN0cmF0aXgxMCBEZWZpbmVzICoqKioqKioqKioqKioqLworCisvKiBT dHJhdGl4MTAgRUNDIE1hbmFnZXIgRGVmaW5lcyAqLworI2RlZmluZSBTMTBfU1lTTUdSX0VDQ19J TlRNQVNLX1ZBTF9PRlNUICAgMHhGRkQxMjA5MAorI2RlZmluZSBTMTBfU1lTTUdSX0VDQ19JTlRN QVNLX1NFVF9PRlNUICAgMHhGRkQxMjA5NAorI2RlZmluZSBTMTBfU1lTTUdSX0VDQ19JTlRNQVNL X0NMUl9PRlNUICAgMHhGRkQxMjA5OAorCisjZGVmaW5lIFMxMF9TWVNNR1JfRUNDX0lOVFNUQVRf U0VSUl9PRlNUICAweEZGRDEyMDlDCisjZGVmaW5lIFMxMF9TWVNNR1JfRUNDX0lOVFNUQVRfREVS Ul9PRlNUICAweEZGRDEyMEEwCisKIHN0cnVjdCBhbHRyX2VkYWNfZGV2aWNlX2RldjsKIAogc3Ry dWN0IGVkYWNfZGV2aWNlX3Bydl9kYXRhIHsKQEAgLTM0MCw0ICszNzcsODEgQEAgc3RydWN0IGFs dHJfYXJyaWExMF9lZGFjIHsKIAlzdHJ1Y3QgbGlzdF9oZWFkCWExMF9lY2NfZGV2aWNlczsKIH07 CiAKKy8qCisgKiBGdW5jdGlvbnMgc3BlY2lmaWVkIGJ5IEFSTSBTTUMgQ2FsbGluZyBjb252ZW50 aW9uOgorICoKKyAqIEZBU1QgY2FsbCBleGVjdXRlcyBhdG9taWMgb3BlcmF0aW9ucywgcmV0dXJu cyB3aGVuIHRoZSByZXF1ZXN0ZWQgb3BlcmF0aW9uCisgKiBoYXMgY29tcGxldGVkLgorICogU1RE IGNhbGwgc3RhcnRzIGEgb3BlcmF0aW9uIHdoaWNoIGNhbiBiZSBwcmVlbXB0ZWQgYnkgYSBub24t c2VjdXJlCisgKiBpbnRlcnJ1cHQuIFRoZSBjYWxsIGNhbiByZXR1cm4gYmVmb3JlIHRoZSByZXF1 ZXN0ZWQgb3BlcmF0aW9uIGhhcworICogY29tcGxldGVkLgorICoKKyAqIGEwLi5hNyBpcyB1c2Vk IGFzIHJlZ2lzdGVyIG5hbWVzIGluIHRoZSBkZXNjcmlwdGlvbnMgYmVsb3csIG9uIGFybTMyCisg KiB0aGF0IHRyYW5zbGF0ZXMgdG8gcjAuLnI3IGFuZCBvbiBhcm02NCB0byB3MC4udzcuCisgKi8K KworI2RlZmluZSBJTlRFTF9TSVBfU01DX1NURF9DQUxMX1ZBTChmdW5jX251bSkgXAorCUFSTV9T TUNDQ19DQUxMX1ZBTChBUk1fU01DQ0NfU1REX0NBTEwsIEFSTV9TTUNDQ19TTUNfNjQsIFwKKwlB Uk1fU01DQ0NfT1dORVJfU0lQLCAoZnVuY19udW0pKQorCisjZGVmaW5lIElOVEVMX1NJUF9TTUNf RkFTVF9DQUxMX1ZBTChmdW5jX251bSkgXAorCUFSTV9TTUNDQ19DQUxMX1ZBTChBUk1fU01DQ0Nf RkFTVF9DQUxMLCBBUk1fU01DQ0NfU01DXzY0LCBcCisJQVJNX1NNQ0NDX09XTkVSX1NJUCwgKGZ1 bmNfbnVtKSkKKworI2RlZmluZSBJTlRFTF9TSVBfU01DX1JFVFVSTl9VTktOT1dOX0ZVTkNUSU9O CQkweEZGRkZGRkZGCisjZGVmaW5lIElOVEVMX1NJUF9TTUNfU1RBVFVTX09LCQkJCTB4MAorI2Rl ZmluZSBJTlRFTF9TSVBfU01DX1JFR19FUlJPUgkJCQkweDUKKworLyoKKyAqIFJlcXVlc3QgSU5U RUxfU0lQX1NNQ19SRUdfUkVBRAorICoKKyAqIFJlYWQgYSBwcm90ZWN0ZWQgcmVnaXN0ZXIgdXNp bmcgU01DQ0MKKyAqCisgKiBDYWxsIHJlZ2lzdGVyIHVzYWdlOgorICogYTA6IElOVEVMX1NJUF9T TUNfUkVHX1JFQUQuCisgKiBhMTogcmVnaXN0ZXIgYWRkcmVzcy4KKyAqIGEyLTc6IG5vdCB1c2Vk LgorICoKKyAqIFJldHVybiBzdGF0dXM6CisgKiBhMDogSU5URUxfU0lQX1NNQ19TVEFUVVNfT0ss IElOVEVMX1NJUF9TTUNfUkVHX0VSUk9SLCBvcgorICogICAgIElOVEVMX1NJUF9TTUNfUkVUVVJO X1VOS05PV05fRlVOQ1RJT04KKyAqIGExOiBWYWx1ZSBpbiB0aGUgcmVnaXN0ZXIKKyAqIGEyLTM6 IG5vdCB1c2VkLgorICovCisjZGVmaW5lIElOVEVMX1NJUF9TTUNfRlVOQ0lEX1JFR19SRUFEIDcK KyNkZWZpbmUgSU5URUxfU0lQX1NNQ19SRUdfUkVBRCBcCisJSU5URUxfU0lQX1NNQ19GQVNUX0NB TExfVkFMKElOVEVMX1NJUF9TTUNfRlVOQ0lEX1JFR19SRUFEKQorCisvKgorICogUmVxdWVzdCBJ TlRFTF9TSVBfU01DX1JFR19XUklURQorICoKKyAqIFdyaXRlIGEgcHJvdGVjdGVkIHJlZ2lzdGVy IHVzaW5nIFNNQ0NDCisgKgorICogQ2FsbCByZWdpc3RlciB1c2FnZToKKyAqIGEwOiBJTlRFTF9T SVBfU01DX1JFR19XUklURS4KKyAqIGExOiByZWdpc3RlciBhZGRyZXNzCisgKiBhMjogdmFsdWUg dG8gcHJvZ3JhbSBpbnRvIHJlZ2lzdGVyLgorICogYTMtNzogbm90IHVzZWQuCisgKgorICogUmV0 dXJuIHN0YXR1czoKKyAqIGEwOiBJTlRFTF9TSVBfU01DX1NUQVRVU19PSywgSU5URUxfU0lQX1NN Q19SRUdfRVJST1IsIG9yCisgKiAgICAgSU5URUxfU0lQX1NNQ19SRVRVUk5fVU5LTk9XTl9GVU5D VElPTgorICogYTEtMzogbm90IHVzZWQuCisgKi8KKyNkZWZpbmUgSU5URUxfU0lQX1NNQ19GVU5D SURfUkVHX1dSSVRFIDgKKyNkZWZpbmUgSU5URUxfU0lQX1NNQ19SRUdfV1JJVEUgXAorCUlOVEVM X1NJUF9TTUNfRkFTVF9DQUxMX1ZBTChJTlRFTF9TSVBfU01DX0ZVTkNJRF9SRUdfV1JJVEUpCisK K3N0cnVjdCBhbHRyX3N0cmF0aXgxMF9lZGFjIHsKKwlzdHJ1Y3QgZGV2aWNlCQkqZGV2OworCXN0 cnVjdCByZWdtYXAJCSplY2NfbWdyX21hcDsKKwlpbnQgc2JfaXJxOworCWludCBkYl9pcnE7CisJ c3RydWN0IGlycV9kb21haW4JKmRvbWFpbjsKKwlzdHJ1Y3QgaXJxX2NoaXAJCWlycV9jaGlwOwor CXN0cnVjdCBsaXN0X2hlYWQJczEwX2VjY19kZXZpY2VzOworCS8qIFNwaW5sb2NrIHByb3RlY3Rz IFNNQyBjYWxscyAqLworCXNwaW5sb2NrX3QJCWxvY2s7Cit9OworCiAjZW5kaWYJLyogI2lmbmRl ZiBfQUxURVJBX0VEQUNfSCAqLwo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: thor.thayer@linux.intel.com (thor.thayer at linux.intel.com) Date: Tue, 24 Apr 2018 13:35:58 -0500 Subject: [PATCH 2/3] edac: altera: Add support for Stratix10 SDRAM EDAC In-Reply-To: <1524594959-5259-1-git-send-email-thor.thayer@linux.intel.com> References: <1524594959-5259-1-git-send-email-thor.thayer@linux.intel.com> Message-ID: <1524594959-5259-3-git-send-email-thor.thayer@linux.intel.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org From: Thor Thayer Add support for SDRAM ECC on the Stratix10 platform to the EDAC device driver. Although Stratix10 is very similar to the Arria10, hypervisor support for Stratix10 SDRAM ECC requires the use of SMC calls to a higher priority exception level to handle some register reads/writes. Signed-off-by: Thor Thayer --- drivers/edac/Kconfig | 2 +- drivers/edac/altera_edac.c | 459 +++++++++++++++++++++++++++++++++++++++++++++ drivers/edac/altera_edac.h | 114 +++++++++++ 3 files changed, 574 insertions(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 3c4017007647..3c66b02b2473 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -379,7 +379,7 @@ config EDAC_THUNDERX config EDAC_ALTERA bool "Altera SOCFPGA ECC" - depends on EDAC=y && ARCH_SOCFPGA + depends on EDAC=y && (ARCH_SOCFPGA || ARM64) help Support for error detection and correction on the Altera SOCs. This must be selected for SDRAM ECC. diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 11d6419788c2..7ed885379719 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2017-2018, Intel Corporation * Copyright Altera Corporation (C) 2014-2016. All rights reserved. * Copyright 2011-2012 Calxeda, Inc. * @@ -80,6 +81,25 @@ static const struct altr_sdram_prv_data a10_data = { .ue_set_mask = A10_DIAGINT_TDERRA_MASK, }; +static const struct altr_sdram_prv_data s10_data = { + .ecc_ctrl_offset = S10_ECCCTRL1_OFST, + .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN, + .ecc_stat_offset = S10_INTSTAT_OFST, + .ecc_stat_ce_mask = A10_INTSTAT_SBEERR, + .ecc_stat_ue_mask = A10_INTSTAT_DBEERR, + .ecc_saddr_offset = S10_SERRADDR_OFST, + .ecc_daddr_offset = S10_DERRADDR_OFST, + .ecc_irq_en_offset = S10_ERRINTEN_OFST, + .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK, + .ecc_irq_clr_offset = S10_INTSTAT_OFST, + .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR), + .ecc_cnt_rst_offset = S10_ECCCTRL1_OFST, + .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK, + .ce_ue_trgr_offset = S10_DIAGINTTEST_OFST, + .ce_set_mask = A10_DIAGINT_TSERRA_MASK, + .ue_set_mask = A10_DIAGINT_TDERRA_MASK, +}; + /*********************** EDAC Memory Controller Functions ****************/ /* The SDRAM controller uses the EDAC Memory Controller framework. */ @@ -231,6 +251,7 @@ static unsigned long get_total_mem(void) static const struct of_device_id altr_sdram_ctrl_of_match[] = { { .compatible = "altr,sdram-edac", .data = &c5_data}, { .compatible = "altr,sdram-edac-a10", .data = &a10_data}, + { .compatible = "altr,sdram-edac-s10", .data = &s10_data}, {}, }; MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); @@ -477,6 +498,292 @@ static int altr_sdram_remove(struct platform_device *pdev) return 0; } +/**************** Stratix 10 EDAC Memory Controller Functions ************/ + +/** + * s10_protected_reg_write + * Write to a protected SMC register. + * @context: Not used. + * @reg: Address of register + * @value: Value to write + * Return: INTEL_SIP_SMC_STATUS_OK (0) on success + * INTEL_SIP_SMC_REG_ERROR on error + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported + */ +static int s10_protected_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct arm_smccc_res result; + + arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, reg, val, 0, 0, + 0, 0, 0, &result); + + return (int)result.a0; +} + +/** + * s10_protected_reg_read + * Read the status of a protected SMC register + * @context: Not used. + * @reg: Address of register + * @value: Value read. + * Return: INTEL_SIP_SMC_STATUS_OK (0) on success + * INTEL_SIP_SMC_REG_ERROR on error + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported + */ +static int s10_protected_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct arm_smccc_res result; + + arm_smccc_smc(INTEL_SIP_SMC_REG_READ, reg, 0, 0, 0, + 0, 0, 0, &result); + + *val = (unsigned int)result.a1; + + return (int)result.a0; +} + +static bool s10_sdram_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S10_ECCCTRL1_OFST: + case S10_ERRINTEN_OFST: + case S10_INTMODE_OFST: + case S10_INTSTAT_OFST: + case S10_DIAGINTTEST_OFST: + case S10_SYSMGR_ECC_INTMASK_VAL_OFST: + case S10_SYSMGR_ECC_INTMASK_SET_OFST: + case S10_SYSMGR_ECC_INTMASK_CLR_OFST: + return true; + } + return false; +} + +static bool s10_sdram_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S10_ECCCTRL1_OFST: + case S10_ERRINTEN_OFST: + case S10_INTMODE_OFST: + case S10_INTSTAT_OFST: + case S10_DERRADDR_OFST: + case S10_SERRADDR_OFST: + case S10_DIAGINTTEST_OFST: + case S10_SYSMGR_ECC_INTMASK_VAL_OFST: + case S10_SYSMGR_ECC_INTMASK_SET_OFST: + case S10_SYSMGR_ECC_INTMASK_CLR_OFST: + case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: + case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: + return true; + } + return false; +} + +static bool s10_sdram_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S10_ECCCTRL1_OFST: + case S10_ERRINTEN_OFST: + case S10_INTMODE_OFST: + case S10_INTSTAT_OFST: + case S10_DERRADDR_OFST: + case S10_SERRADDR_OFST: + case S10_DIAGINTTEST_OFST: + case S10_SYSMGR_ECC_INTMASK_VAL_OFST: + case S10_SYSMGR_ECC_INTMASK_SET_OFST: + case S10_SYSMGR_ECC_INTMASK_CLR_OFST: + case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: + case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: + return true; + } + return false; +} + +static const struct regmap_config s10_sdram_regmap_cfg = { + .name = "s10_ddr", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xffffffff, + .writeable_reg = s10_sdram_writeable_reg, + .readable_reg = s10_sdram_readable_reg, + .volatile_reg = s10_sdram_volatile_reg, + .reg_read = s10_protected_reg_read, + .reg_write = s10_protected_reg_write, + .use_single_rw = true, +}; + +static int altr_s10_sdram_probe(struct platform_device *pdev) +{ + const struct of_device_id *id; + struct edac_mc_layer layers[2]; + struct mem_ctl_info *mci; + struct altr_sdram_mc_data *drvdata; + const struct altr_sdram_prv_data *priv; + struct regmap *regmap; + struct dimm_info *dimm; + u32 read_reg; + struct resource *res; + int irq, ret = 0; + unsigned long mem_size; + void __iomem *reg_base; + + id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev); + if (!id) + return -ENODEV; + + /* Grab specific offsets and masks for Stratix10 */ + priv = of_match_node(altr_sdram_ctrl_of_match, + pdev->dev.of_node)->data; + /* Grab the register range from the sdr controller in device tree */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + + regmap = devm_regmap_init(&pdev->dev, NULL, (void *)priv, + &s10_sdram_regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Validate the SDRAM controller has ECC enabled */ + if (regmap_read(regmap, priv->ecc_ctrl_offset, &read_reg) || + ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) { + edac_printk(KERN_ERR, EDAC_MC, + "No ECC/ECC disabled [0x%08X]\n", read_reg); + return -ENODEV; + } + + /* Grab memory size from device tree. */ + mem_size = get_total_mem(); + if (!mem_size) { + edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n"); + return -ENODEV; + } + + /* Ensure the SDRAM Interrupt is disabled */ + if (regmap_update_bits(regmap, priv->ecc_irq_en_offset, + priv->ecc_irq_en_mask, 0)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error disabling SDRAM ECC IRQ\n"); + return -ENODEV; + } + + /* Toggle to clear the SDRAM Error count */ + if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, + priv->ecc_cnt_rst_mask, + priv->ecc_cnt_rst_mask)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error clearing SDRAM ECC count\n"); + return -ENODEV; + } + + if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, + priv->ecc_cnt_rst_mask, 0)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error clearing SDRAM ECC count\n"); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + edac_printk(KERN_ERR, EDAC_MC, + "No irq %d in DT\n", irq); + return -ENODEV; + } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = 1; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = 1; + layers[1].is_virt_csrow = false; + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, + sizeof(struct altr_sdram_mc_data)); + if (!mci) + return -ENOMEM; + + mci->pdev = &pdev->dev; + drvdata = mci->pvt_info; + drvdata->mc_vbase = regmap; + drvdata->data = priv; + platform_set_drvdata(pdev, mci); + + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { + edac_printk(KERN_ERR, EDAC_MC, + "Unable to get managed device resource\n"); + ret = -ENOMEM; + goto free; + } + + mci->mtype_cap = MEM_FLAG_DDR3; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = EDAC_MOD_STR; + mci->ctl_name = dev_name(&pdev->dev); + mci->scrub_mode = SCRUB_SW_SRC; + mci->dev_name = dev_name(&pdev->dev); + + dimm = *mci->dimms; + dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1; + dimm->grain = 8; + dimm->dtype = DEV_X8; + dimm->mtype = MEM_DDR3; + dimm->edac_mode = EDAC_SECDED; + + ret = edac_mc_add_mc(mci); + if (ret < 0) + goto err; + + ret = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler, + IRQF_SHARED, dev_name(&pdev->dev), mci); + if (ret < 0) { + edac_mc_printk(mci, KERN_ERR, + "Unable to request irq %d\n", irq); + ret = -ENODEV; + goto err2; + } + + if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset, + priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) { + edac_mc_printk(mci, KERN_ERR, + "Error enabling SDRAM ECC IRQ\n"); + ret = -ENODEV; + goto err2; + } + + altr_sdr_mc_create_debugfs_nodes(mci); + + devres_close_group(&pdev->dev, NULL); + + return 0; + +err2: + edac_mc_del_mc(&pdev->dev); +err: + devres_release_group(&pdev->dev, NULL); +free: + edac_mc_free(mci); + edac_printk(KERN_ERR, EDAC_MC, + "EDAC Probe Failed; Error %d\n", ret); + + return ret; +} + +static int altr_s10_sdram_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +/************** ***********/ + /* * If you want to suspend, need to disable EDAC by removing it * from the device tree or defconfig. @@ -508,6 +815,20 @@ static struct platform_driver altr_sdram_edac_driver = { module_platform_driver(altr_sdram_edac_driver); +static struct platform_driver altr_s10_sdram_edac_driver = { + .probe = altr_s10_sdram_probe, + .remove = altr_s10_sdram_remove, + .driver = { + .name = "altr_s10_sdram_edac", +#ifdef CONFIG_PM + .pm = &altr_sdram_pm_ops, +#endif + .of_match_table = altr_sdram_ctrl_of_match, + }, +}; + +module_platform_driver(altr_s10_sdram_edac_driver); + /************************* EDAC Parent Probe *************************/ static const struct of_device_id altr_edac_device_of_match[]; @@ -1925,6 +2246,144 @@ static struct platform_driver altr_edac_a10_driver = { }; module_platform_driver(altr_edac_a10_driver); +/************** Stratix 10 EDAC Device Controller Functions> ************/ + +static void altr_edac_s10_irq_handler(struct irq_desc *desc) +{ + int dberr, bit, sm_offset, irq_status; + unsigned long flags; + struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + int irq = irq_desc_get_irq(desc); + + spin_lock_irqsave(&edac->lock, flags); + dberr = (irq == edac->db_irq) ? 1 : 0; + sm_offset = dberr ? S10_SYSMGR_ECC_INTSTAT_DERR_OFST : + S10_SYSMGR_ECC_INTSTAT_SERR_OFST; + + chained_irq_enter(chip, desc); + + s10_protected_reg_read(NULL, sm_offset, &irq_status); + + for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { + irq = irq_linear_revmap(edac->domain, dberr * 32 + bit); + if (irq) + generic_handle_irq(irq); + } + + chained_irq_exit(chip, desc); + spin_unlock_irqrestore(&edac->lock, flags); +} + +static void s10_eccmgr_irq_mask(struct irq_data *d) +{ + struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); + + s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_SET_OFST, + BIT(d->hwirq)); +} + +static void s10_eccmgr_irq_unmask(struct irq_data *d) +{ + struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); + + s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_CLR_OFST, + BIT(d->hwirq)); +} + +static int s10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct altr_stratix10_edac *edac = d->host_data; + + irq_set_chip_and_handler(irq, &edac->irq_chip, handle_simple_irq); + irq_set_chip_data(irq, edac); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops s10_eccmgr_ic_ops = { + .map = s10_eccmgr_irqdomain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int altr_edac_s10_probe(struct platform_device *pdev) +{ + struct altr_stratix10_edac *edac; + struct device_node *child; + + edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); + if (!edac) + return -ENOMEM; + + edac->dev = &pdev->dev; + platform_set_drvdata(pdev, edac); + INIT_LIST_HEAD(&edac->s10_ecc_devices); + spin_lock_init(&edac->lock); + + edac->ecc_mgr_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "altr,sysmgr-syscon"); + if (IS_ERR(edac->ecc_mgr_map)) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "Unable to get syscon altr,sysmgr-syscon\n"); + return PTR_ERR(edac->ecc_mgr_map); + } + + edac->irq_chip.name = pdev->dev.of_node->name; + edac->irq_chip.irq_mask = s10_eccmgr_irq_mask; + edac->irq_chip.irq_unmask = s10_eccmgr_irq_unmask; + edac->domain = irq_domain_add_linear(pdev->dev.of_node, 64, + &s10_eccmgr_ic_ops, edac); + if (!edac->domain) { + dev_err(&pdev->dev, "Error adding IRQ domain\n"); + return -ENOMEM; + } + + edac->sb_irq = platform_get_irq(pdev, 0); + if (edac->sb_irq < 0) { + dev_err(&pdev->dev, "No SBERR IRQ resource\n"); + return edac->sb_irq; + } + + irq_set_chained_handler_and_data(edac->sb_irq, + altr_edac_s10_irq_handler, + edac); + + edac->db_irq = platform_get_irq(pdev, 1); + if (edac->db_irq >= 0) + irq_set_chained_handler_and_data(edac->db_irq, + altr_edac_s10_irq_handler, + edac); + + for_each_child_of_node(pdev->dev.of_node, child) { + if (!of_device_is_available(child)) + continue; + + if (of_device_is_compatible(child, "altr,sdram-edac-s10")) + of_platform_populate(pdev->dev.of_node, + altr_sdram_ctrl_of_match, + NULL, &pdev->dev); + } + + return 0; +} + +static const struct of_device_id altr_edac_s10_of_match[] = { + { .compatible = "altr,socfpga-s10-ecc-manager" }, + {}, +}; +MODULE_DEVICE_TABLE(of, altr_edac_s10_of_match); + +static struct platform_driver altr_edac_s10_driver = { + .probe = altr_edac_s10_probe, + .driver = { + .name = "socfpga_s10_ecc_manager", + .of_match_table = altr_edac_s10_of_match, + }, +}; +module_platform_driver(altr_edac_s10_driver); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Thor Thayer"); MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index cbc96290f743..1024528dc67a 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -18,6 +18,7 @@ #ifndef _ALTERA_EDAC_H #define _ALTERA_EDAC_H +#include #include #include @@ -94,6 +95,7 @@ /* SDRAM Controller Address Width Register */ #define CV_DRAMADDRW 0xFFC2502C #define A10_DRAMADDRW 0xFFCFA0A8 +#define S10_DRAMADDRW 0xF80110E0 /* SDRAM Controller Address Widths Field Register */ #define DRAMADDRW_COLBIT_MASK 0x001F @@ -115,6 +117,7 @@ /* SDRAM Controller Interface Data Width Register */ #define CV_DRAMIFWIDTH 0xFFC25030 #define A10_DRAMIFWIDTH 0xFFCFB008 +#define S10_DRAMIFWIDTH 0xF8011008 /* SDRAM Controller Interface Data Width Defines */ #define CV_DRAMIFWIDTH_16B_ECC 24 @@ -164,6 +167,30 @@ #define A10_INTMASK_CLR_OFST 0x10 #define A10_DDR0_IRQ_MASK BIT(17) +/************* Stratix10 Defines **************/ + +/* SDRAM Controller EccCtrl Register */ +#define S10_ECCCTRL1_OFST 0xF8011100 + +/* SDRAM Controller DRAM IRQ Register */ +#define S10_ERRINTEN_OFST 0xF8011110 + +/* SDRAM Interrupt Mode Register */ +#define S10_INTMODE_OFST 0xF801111C + +/* SDRAM Controller Error Status Register */ +#define S10_INTSTAT_OFST 0xF8011120 + +/* SDRAM Controller ECC Error Address Register */ +#define S10_DERRADDR_OFST 0xF801112C +#define S10_SERRADDR_OFST 0xF8011130 + +/* SDRAM Controller ECC Diagnostic Register */ +#define S10_DIAGINTTEST_OFST 0xF8011124 + +/* SDRAM Single Bit Error Count Compare Set Register */ +#define S10_SERRCNTREG_OFST 0xF801113C + struct altr_sdram_prv_data { int ecc_ctrl_offset; int ecc_ctl_en_mask; @@ -296,6 +323,16 @@ struct altr_sdram_mc_data { /* A10 ECC Controller memory initialization timeout */ #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 +/************* Stratix10 Defines **************/ + +/* Stratix10 ECC Manager Defines */ +#define S10_SYSMGR_ECC_INTMASK_VAL_OFST 0xFFD12090 +#define S10_SYSMGR_ECC_INTMASK_SET_OFST 0xFFD12094 +#define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0xFFD12098 + +#define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C +#define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0 + struct altr_edac_device_dev; struct edac_device_prv_data { @@ -340,4 +377,81 @@ struct altr_arria10_edac { struct list_head a10_ecc_devices; }; +/* + * Functions specified by ARM SMC Calling convention: + * + * FAST call executes atomic operations, returns when the requested operation + * has completed. + * STD call starts a operation which can be preempted by a non-secure + * interrupt. The call can return before the requested operation has + * completed. + * + * a0..a7 is used as register names in the descriptions below, on arm32 + * that translates to r0..r7 and on arm64 to w0..w7. + */ + +#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, (func_num)) + +#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, (func_num)) + +#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF +#define INTEL_SIP_SMC_STATUS_OK 0x0 +#define INTEL_SIP_SMC_REG_ERROR 0x5 + +/* + * Request INTEL_SIP_SMC_REG_READ + * + * Read a protected register using SMCCC + * + * Call register usage: + * a0: INTEL_SIP_SMC_REG_READ. + * a1: register address. + * a2-7: not used. + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION + * a1: Value in the register + * a2-3: not used. + */ +#define INTEL_SIP_SMC_FUNCID_REG_READ 7 +#define INTEL_SIP_SMC_REG_READ \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ) + +/* + * Request INTEL_SIP_SMC_REG_WRITE + * + * Write a protected register using SMCCC + * + * Call register usage: + * a0: INTEL_SIP_SMC_REG_WRITE. + * a1: register address + * a2: value to program into register. + * a3-7: not used. + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION + * a1-3: not used. + */ +#define INTEL_SIP_SMC_FUNCID_REG_WRITE 8 +#define INTEL_SIP_SMC_REG_WRITE \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE) + +struct altr_stratix10_edac { + struct device *dev; + struct regmap *ecc_mgr_map; + int sb_irq; + int db_irq; + struct irq_domain *domain; + struct irq_chip irq_chip; + struct list_head s10_ecc_devices; + /* Spinlock protects SMC calls */ + spinlock_t lock; +}; + #endif /* #ifndef _ALTERA_EDAC_H */ -- 2.7.4 From mboxrd@z Thu Jan 1 00:00:00 1970 From: thor.thayer@linux.intel.com Subject: [PATCH 2/3] edac: altera: Add support for Stratix10 SDRAM EDAC Date: Tue, 24 Apr 2018 13:35:58 -0500 Message-ID: <1524594959-5259-3-git-send-email-thor.thayer@linux.intel.com> References: <1524594959-5259-1-git-send-email-thor.thayer@linux.intel.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1524594959-5259-1-git-send-email-thor.thayer@linux.intel.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: bp@alien8.de, mchehab@kernel.org, robh+dt@kernel.org, mark.rutland@arm.com, dinguyen@kernel.org, catalin.marinas@arm.com, will.deacon@arm.com Cc: devicetree@vger.kernel.org, thor.thayer@linux.intel.com, linux-arm-kernel@lists.infradead.org, linux-edac@vger.kernel.org List-Id: devicetree@vger.kernel.org From: Thor Thayer Add support for SDRAM ECC on the Stratix10 platform to the EDAC device driver. Although Stratix10 is very similar to the Arria10, hypervisor support for Stratix10 SDRAM ECC requires the use of SMC calls to a higher priority exception level to handle some register reads/writes. Signed-off-by: Thor Thayer --- drivers/edac/Kconfig | 2 +- drivers/edac/altera_edac.c | 459 +++++++++++++++++++++++++++++++++++++++++++++ drivers/edac/altera_edac.h | 114 +++++++++++ 3 files changed, 574 insertions(+), 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 3c4017007647..3c66b02b2473 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -379,7 +379,7 @@ config EDAC_THUNDERX config EDAC_ALTERA bool "Altera SOCFPGA ECC" - depends on EDAC=y && ARCH_SOCFPGA + depends on EDAC=y && (ARCH_SOCFPGA || ARM64) help Support for error detection and correction on the Altera SOCs. This must be selected for SDRAM ECC. diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 11d6419788c2..7ed885379719 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2017-2018, Intel Corporation * Copyright Altera Corporation (C) 2014-2016. All rights reserved. * Copyright 2011-2012 Calxeda, Inc. * @@ -80,6 +81,25 @@ static const struct altr_sdram_prv_data a10_data = { .ue_set_mask = A10_DIAGINT_TDERRA_MASK, }; +static const struct altr_sdram_prv_data s10_data = { + .ecc_ctrl_offset = S10_ECCCTRL1_OFST, + .ecc_ctl_en_mask = A10_ECCCTRL1_ECC_EN, + .ecc_stat_offset = S10_INTSTAT_OFST, + .ecc_stat_ce_mask = A10_INTSTAT_SBEERR, + .ecc_stat_ue_mask = A10_INTSTAT_DBEERR, + .ecc_saddr_offset = S10_SERRADDR_OFST, + .ecc_daddr_offset = S10_DERRADDR_OFST, + .ecc_irq_en_offset = S10_ERRINTEN_OFST, + .ecc_irq_en_mask = A10_ECC_IRQ_EN_MASK, + .ecc_irq_clr_offset = S10_INTSTAT_OFST, + .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR), + .ecc_cnt_rst_offset = S10_ECCCTRL1_OFST, + .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK, + .ce_ue_trgr_offset = S10_DIAGINTTEST_OFST, + .ce_set_mask = A10_DIAGINT_TSERRA_MASK, + .ue_set_mask = A10_DIAGINT_TDERRA_MASK, +}; + /*********************** EDAC Memory Controller Functions ****************/ /* The SDRAM controller uses the EDAC Memory Controller framework. */ @@ -231,6 +251,7 @@ static unsigned long get_total_mem(void) static const struct of_device_id altr_sdram_ctrl_of_match[] = { { .compatible = "altr,sdram-edac", .data = &c5_data}, { .compatible = "altr,sdram-edac-a10", .data = &a10_data}, + { .compatible = "altr,sdram-edac-s10", .data = &s10_data}, {}, }; MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match); @@ -477,6 +498,292 @@ static int altr_sdram_remove(struct platform_device *pdev) return 0; } +/**************** Stratix 10 EDAC Memory Controller Functions ************/ + +/** + * s10_protected_reg_write + * Write to a protected SMC register. + * @context: Not used. + * @reg: Address of register + * @value: Value to write + * Return: INTEL_SIP_SMC_STATUS_OK (0) on success + * INTEL_SIP_SMC_REG_ERROR on error + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported + */ +static int s10_protected_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct arm_smccc_res result; + + arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, reg, val, 0, 0, + 0, 0, 0, &result); + + return (int)result.a0; +} + +/** + * s10_protected_reg_read + * Read the status of a protected SMC register + * @context: Not used. + * @reg: Address of register + * @value: Value read. + * Return: INTEL_SIP_SMC_STATUS_OK (0) on success + * INTEL_SIP_SMC_REG_ERROR on error + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported + */ +static int s10_protected_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct arm_smccc_res result; + + arm_smccc_smc(INTEL_SIP_SMC_REG_READ, reg, 0, 0, 0, + 0, 0, 0, &result); + + *val = (unsigned int)result.a1; + + return (int)result.a0; +} + +static bool s10_sdram_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S10_ECCCTRL1_OFST: + case S10_ERRINTEN_OFST: + case S10_INTMODE_OFST: + case S10_INTSTAT_OFST: + case S10_DIAGINTTEST_OFST: + case S10_SYSMGR_ECC_INTMASK_VAL_OFST: + case S10_SYSMGR_ECC_INTMASK_SET_OFST: + case S10_SYSMGR_ECC_INTMASK_CLR_OFST: + return true; + } + return false; +} + +static bool s10_sdram_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S10_ECCCTRL1_OFST: + case S10_ERRINTEN_OFST: + case S10_INTMODE_OFST: + case S10_INTSTAT_OFST: + case S10_DERRADDR_OFST: + case S10_SERRADDR_OFST: + case S10_DIAGINTTEST_OFST: + case S10_SYSMGR_ECC_INTMASK_VAL_OFST: + case S10_SYSMGR_ECC_INTMASK_SET_OFST: + case S10_SYSMGR_ECC_INTMASK_CLR_OFST: + case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: + case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: + return true; + } + return false; +} + +static bool s10_sdram_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S10_ECCCTRL1_OFST: + case S10_ERRINTEN_OFST: + case S10_INTMODE_OFST: + case S10_INTSTAT_OFST: + case S10_DERRADDR_OFST: + case S10_SERRADDR_OFST: + case S10_DIAGINTTEST_OFST: + case S10_SYSMGR_ECC_INTMASK_VAL_OFST: + case S10_SYSMGR_ECC_INTMASK_SET_OFST: + case S10_SYSMGR_ECC_INTMASK_CLR_OFST: + case S10_SYSMGR_ECC_INTSTAT_SERR_OFST: + case S10_SYSMGR_ECC_INTSTAT_DERR_OFST: + return true; + } + return false; +} + +static const struct regmap_config s10_sdram_regmap_cfg = { + .name = "s10_ddr", + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xffffffff, + .writeable_reg = s10_sdram_writeable_reg, + .readable_reg = s10_sdram_readable_reg, + .volatile_reg = s10_sdram_volatile_reg, + .reg_read = s10_protected_reg_read, + .reg_write = s10_protected_reg_write, + .use_single_rw = true, +}; + +static int altr_s10_sdram_probe(struct platform_device *pdev) +{ + const struct of_device_id *id; + struct edac_mc_layer layers[2]; + struct mem_ctl_info *mci; + struct altr_sdram_mc_data *drvdata; + const struct altr_sdram_prv_data *priv; + struct regmap *regmap; + struct dimm_info *dimm; + u32 read_reg; + struct resource *res; + int irq, ret = 0; + unsigned long mem_size; + void __iomem *reg_base; + + id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev); + if (!id) + return -ENODEV; + + /* Grab specific offsets and masks for Stratix10 */ + priv = of_match_node(altr_sdram_ctrl_of_match, + pdev->dev.of_node)->data; + /* Grab the register range from the sdr controller in device tree */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(reg_base)) + return PTR_ERR(reg_base); + + regmap = devm_regmap_init(&pdev->dev, NULL, (void *)priv, + &s10_sdram_regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Validate the SDRAM controller has ECC enabled */ + if (regmap_read(regmap, priv->ecc_ctrl_offset, &read_reg) || + ((read_reg & priv->ecc_ctl_en_mask) != priv->ecc_ctl_en_mask)) { + edac_printk(KERN_ERR, EDAC_MC, + "No ECC/ECC disabled [0x%08X]\n", read_reg); + return -ENODEV; + } + + /* Grab memory size from device tree. */ + mem_size = get_total_mem(); + if (!mem_size) { + edac_printk(KERN_ERR, EDAC_MC, "Unable to calculate memory size\n"); + return -ENODEV; + } + + /* Ensure the SDRAM Interrupt is disabled */ + if (regmap_update_bits(regmap, priv->ecc_irq_en_offset, + priv->ecc_irq_en_mask, 0)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error disabling SDRAM ECC IRQ\n"); + return -ENODEV; + } + + /* Toggle to clear the SDRAM Error count */ + if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, + priv->ecc_cnt_rst_mask, + priv->ecc_cnt_rst_mask)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error clearing SDRAM ECC count\n"); + return -ENODEV; + } + + if (regmap_update_bits(regmap, priv->ecc_cnt_rst_offset, + priv->ecc_cnt_rst_mask, 0)) { + edac_printk(KERN_ERR, EDAC_MC, + "Error clearing SDRAM ECC count\n"); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + edac_printk(KERN_ERR, EDAC_MC, + "No irq %d in DT\n", irq); + return -ENODEV; + } + + layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; + layers[0].size = 1; + layers[0].is_virt_csrow = true; + layers[1].type = EDAC_MC_LAYER_CHANNEL; + layers[1].size = 1; + layers[1].is_virt_csrow = false; + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, + sizeof(struct altr_sdram_mc_data)); + if (!mci) + return -ENOMEM; + + mci->pdev = &pdev->dev; + drvdata = mci->pvt_info; + drvdata->mc_vbase = regmap; + drvdata->data = priv; + platform_set_drvdata(pdev, mci); + + if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { + edac_printk(KERN_ERR, EDAC_MC, + "Unable to get managed device resource\n"); + ret = -ENOMEM; + goto free; + } + + mci->mtype_cap = MEM_FLAG_DDR3; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_cap = EDAC_FLAG_SECDED; + mci->mod_name = EDAC_MOD_STR; + mci->ctl_name = dev_name(&pdev->dev); + mci->scrub_mode = SCRUB_SW_SRC; + mci->dev_name = dev_name(&pdev->dev); + + dimm = *mci->dimms; + dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1; + dimm->grain = 8; + dimm->dtype = DEV_X8; + dimm->mtype = MEM_DDR3; + dimm->edac_mode = EDAC_SECDED; + + ret = edac_mc_add_mc(mci); + if (ret < 0) + goto err; + + ret = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler, + IRQF_SHARED, dev_name(&pdev->dev), mci); + if (ret < 0) { + edac_mc_printk(mci, KERN_ERR, + "Unable to request irq %d\n", irq); + ret = -ENODEV; + goto err2; + } + + if (regmap_update_bits(drvdata->mc_vbase, priv->ecc_irq_en_offset, + priv->ecc_irq_en_mask, priv->ecc_irq_en_mask)) { + edac_mc_printk(mci, KERN_ERR, + "Error enabling SDRAM ECC IRQ\n"); + ret = -ENODEV; + goto err2; + } + + altr_sdr_mc_create_debugfs_nodes(mci); + + devres_close_group(&pdev->dev, NULL); + + return 0; + +err2: + edac_mc_del_mc(&pdev->dev); +err: + devres_release_group(&pdev->dev, NULL); +free: + edac_mc_free(mci); + edac_printk(KERN_ERR, EDAC_MC, + "EDAC Probe Failed; Error %d\n", ret); + + return ret; +} + +static int altr_s10_sdram_remove(struct platform_device *pdev) +{ + struct mem_ctl_info *mci = platform_get_drvdata(pdev); + + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +/************** ***********/ + /* * If you want to suspend, need to disable EDAC by removing it * from the device tree or defconfig. @@ -508,6 +815,20 @@ static struct platform_driver altr_sdram_edac_driver = { module_platform_driver(altr_sdram_edac_driver); +static struct platform_driver altr_s10_sdram_edac_driver = { + .probe = altr_s10_sdram_probe, + .remove = altr_s10_sdram_remove, + .driver = { + .name = "altr_s10_sdram_edac", +#ifdef CONFIG_PM + .pm = &altr_sdram_pm_ops, +#endif + .of_match_table = altr_sdram_ctrl_of_match, + }, +}; + +module_platform_driver(altr_s10_sdram_edac_driver); + /************************* EDAC Parent Probe *************************/ static const struct of_device_id altr_edac_device_of_match[]; @@ -1925,6 +2246,144 @@ static struct platform_driver altr_edac_a10_driver = { }; module_platform_driver(altr_edac_a10_driver); +/************** Stratix 10 EDAC Device Controller Functions> ************/ + +static void altr_edac_s10_irq_handler(struct irq_desc *desc) +{ + int dberr, bit, sm_offset, irq_status; + unsigned long flags; + struct altr_stratix10_edac *edac = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + int irq = irq_desc_get_irq(desc); + + spin_lock_irqsave(&edac->lock, flags); + dberr = (irq == edac->db_irq) ? 1 : 0; + sm_offset = dberr ? S10_SYSMGR_ECC_INTSTAT_DERR_OFST : + S10_SYSMGR_ECC_INTSTAT_SERR_OFST; + + chained_irq_enter(chip, desc); + + s10_protected_reg_read(NULL, sm_offset, &irq_status); + + for_each_set_bit(bit, (unsigned long *)&irq_status, 32) { + irq = irq_linear_revmap(edac->domain, dberr * 32 + bit); + if (irq) + generic_handle_irq(irq); + } + + chained_irq_exit(chip, desc); + spin_unlock_irqrestore(&edac->lock, flags); +} + +static void s10_eccmgr_irq_mask(struct irq_data *d) +{ + struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); + + s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_SET_OFST, + BIT(d->hwirq)); +} + +static void s10_eccmgr_irq_unmask(struct irq_data *d) +{ + struct altr_stratix10_edac *edac = irq_data_get_irq_chip_data(d); + + s10_protected_reg_write(edac, S10_SYSMGR_ECC_INTMASK_CLR_OFST, + BIT(d->hwirq)); +} + +static int s10_eccmgr_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct altr_stratix10_edac *edac = d->host_data; + + irq_set_chip_and_handler(irq, &edac->irq_chip, handle_simple_irq); + irq_set_chip_data(irq, edac); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops s10_eccmgr_ic_ops = { + .map = s10_eccmgr_irqdomain_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int altr_edac_s10_probe(struct platform_device *pdev) +{ + struct altr_stratix10_edac *edac; + struct device_node *child; + + edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL); + if (!edac) + return -ENOMEM; + + edac->dev = &pdev->dev; + platform_set_drvdata(pdev, edac); + INIT_LIST_HEAD(&edac->s10_ecc_devices); + spin_lock_init(&edac->lock); + + edac->ecc_mgr_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "altr,sysmgr-syscon"); + if (IS_ERR(edac->ecc_mgr_map)) { + edac_printk(KERN_ERR, EDAC_DEVICE, + "Unable to get syscon altr,sysmgr-syscon\n"); + return PTR_ERR(edac->ecc_mgr_map); + } + + edac->irq_chip.name = pdev->dev.of_node->name; + edac->irq_chip.irq_mask = s10_eccmgr_irq_mask; + edac->irq_chip.irq_unmask = s10_eccmgr_irq_unmask; + edac->domain = irq_domain_add_linear(pdev->dev.of_node, 64, + &s10_eccmgr_ic_ops, edac); + if (!edac->domain) { + dev_err(&pdev->dev, "Error adding IRQ domain\n"); + return -ENOMEM; + } + + edac->sb_irq = platform_get_irq(pdev, 0); + if (edac->sb_irq < 0) { + dev_err(&pdev->dev, "No SBERR IRQ resource\n"); + return edac->sb_irq; + } + + irq_set_chained_handler_and_data(edac->sb_irq, + altr_edac_s10_irq_handler, + edac); + + edac->db_irq = platform_get_irq(pdev, 1); + if (edac->db_irq >= 0) + irq_set_chained_handler_and_data(edac->db_irq, + altr_edac_s10_irq_handler, + edac); + + for_each_child_of_node(pdev->dev.of_node, child) { + if (!of_device_is_available(child)) + continue; + + if (of_device_is_compatible(child, "altr,sdram-edac-s10")) + of_platform_populate(pdev->dev.of_node, + altr_sdram_ctrl_of_match, + NULL, &pdev->dev); + } + + return 0; +} + +static const struct of_device_id altr_edac_s10_of_match[] = { + { .compatible = "altr,socfpga-s10-ecc-manager" }, + {}, +}; +MODULE_DEVICE_TABLE(of, altr_edac_s10_of_match); + +static struct platform_driver altr_edac_s10_driver = { + .probe = altr_edac_s10_probe, + .driver = { + .name = "socfpga_s10_ecc_manager", + .of_match_table = altr_edac_s10_of_match, + }, +}; +module_platform_driver(altr_edac_s10_driver); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Thor Thayer"); MODULE_DESCRIPTION("EDAC Driver for Altera Memories"); diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index cbc96290f743..1024528dc67a 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -18,6 +18,7 @@ #ifndef _ALTERA_EDAC_H #define _ALTERA_EDAC_H +#include #include #include @@ -94,6 +95,7 @@ /* SDRAM Controller Address Width Register */ #define CV_DRAMADDRW 0xFFC2502C #define A10_DRAMADDRW 0xFFCFA0A8 +#define S10_DRAMADDRW 0xF80110E0 /* SDRAM Controller Address Widths Field Register */ #define DRAMADDRW_COLBIT_MASK 0x001F @@ -115,6 +117,7 @@ /* SDRAM Controller Interface Data Width Register */ #define CV_DRAMIFWIDTH 0xFFC25030 #define A10_DRAMIFWIDTH 0xFFCFB008 +#define S10_DRAMIFWIDTH 0xF8011008 /* SDRAM Controller Interface Data Width Defines */ #define CV_DRAMIFWIDTH_16B_ECC 24 @@ -164,6 +167,30 @@ #define A10_INTMASK_CLR_OFST 0x10 #define A10_DDR0_IRQ_MASK BIT(17) +/************* Stratix10 Defines **************/ + +/* SDRAM Controller EccCtrl Register */ +#define S10_ECCCTRL1_OFST 0xF8011100 + +/* SDRAM Controller DRAM IRQ Register */ +#define S10_ERRINTEN_OFST 0xF8011110 + +/* SDRAM Interrupt Mode Register */ +#define S10_INTMODE_OFST 0xF801111C + +/* SDRAM Controller Error Status Register */ +#define S10_INTSTAT_OFST 0xF8011120 + +/* SDRAM Controller ECC Error Address Register */ +#define S10_DERRADDR_OFST 0xF801112C +#define S10_SERRADDR_OFST 0xF8011130 + +/* SDRAM Controller ECC Diagnostic Register */ +#define S10_DIAGINTTEST_OFST 0xF8011124 + +/* SDRAM Single Bit Error Count Compare Set Register */ +#define S10_SERRCNTREG_OFST 0xF801113C + struct altr_sdram_prv_data { int ecc_ctrl_offset; int ecc_ctl_en_mask; @@ -296,6 +323,16 @@ struct altr_sdram_mc_data { /* A10 ECC Controller memory initialization timeout */ #define ALTR_A10_ECC_INIT_WATCHDOG_10US 10000 +/************* Stratix10 Defines **************/ + +/* Stratix10 ECC Manager Defines */ +#define S10_SYSMGR_ECC_INTMASK_VAL_OFST 0xFFD12090 +#define S10_SYSMGR_ECC_INTMASK_SET_OFST 0xFFD12094 +#define S10_SYSMGR_ECC_INTMASK_CLR_OFST 0xFFD12098 + +#define S10_SYSMGR_ECC_INTSTAT_SERR_OFST 0xFFD1209C +#define S10_SYSMGR_ECC_INTSTAT_DERR_OFST 0xFFD120A0 + struct altr_edac_device_dev; struct edac_device_prv_data { @@ -340,4 +377,81 @@ struct altr_arria10_edac { struct list_head a10_ecc_devices; }; +/* + * Functions specified by ARM SMC Calling convention: + * + * FAST call executes atomic operations, returns when the requested operation + * has completed. + * STD call starts a operation which can be preempted by a non-secure + * interrupt. The call can return before the requested operation has + * completed. + * + * a0..a7 is used as register names in the descriptions below, on arm32 + * that translates to r0..r7 and on arm64 to w0..w7. + */ + +#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, (func_num)) + +#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, (func_num)) + +#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF +#define INTEL_SIP_SMC_STATUS_OK 0x0 +#define INTEL_SIP_SMC_REG_ERROR 0x5 + +/* + * Request INTEL_SIP_SMC_REG_READ + * + * Read a protected register using SMCCC + * + * Call register usage: + * a0: INTEL_SIP_SMC_REG_READ. + * a1: register address. + * a2-7: not used. + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION + * a1: Value in the register + * a2-3: not used. + */ +#define INTEL_SIP_SMC_FUNCID_REG_READ 7 +#define INTEL_SIP_SMC_REG_READ \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ) + +/* + * Request INTEL_SIP_SMC_REG_WRITE + * + * Write a protected register using SMCCC + * + * Call register usage: + * a0: INTEL_SIP_SMC_REG_WRITE. + * a1: register address + * a2: value to program into register. + * a3-7: not used. + * + * Return status: + * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_REG_ERROR, or + * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION + * a1-3: not used. + */ +#define INTEL_SIP_SMC_FUNCID_REG_WRITE 8 +#define INTEL_SIP_SMC_REG_WRITE \ + INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE) + +struct altr_stratix10_edac { + struct device *dev; + struct regmap *ecc_mgr_map; + int sb_irq; + int db_irq; + struct irq_domain *domain; + struct irq_chip irq_chip; + struct list_head s10_ecc_devices; + /* Spinlock protects SMC calls */ + spinlock_t lock; +}; + #endif /* #ifndef _ALTERA_EDAC_H */ -- 2.7.4