From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753659AbbJSTkt (ORCPT ); Mon, 19 Oct 2015 15:40:49 -0400 Received: from mail-bn1bbn0100.outbound.protection.outlook.com ([157.56.111.100]:37643 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751654AbbJSTkq (ORCPT ); Mon, 19 Oct 2015 15:40:46 -0400 X-Greylist: delayed 939 seconds by postgrey-1.27 at vger.kernel.org; Mon, 19 Oct 2015 15:40:45 EDT Authentication-Results: spf=none (sender IP is 165.204.84.222) smtp.mailfrom=amd.com; alien8.de; dkim=none (message not signed) header.d=none;alien8.de; dmarc=permerror action=none header.from=amd.com; X-WSS-ID: 0NWHF9K-08-2LI-02 X-M-MSG: From: Brijesh Singh To: , CC: , , , , , , , , , Brijesh Singh Subject: [PATCH] EDAC: Add AMD Seattle SoC EDAC Date: Mon, 19 Oct 2015 14:23:17 -0500 Message-ID: <1445282597-18999-1-git-send-email-brijeshkumar.singh@amd.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.180.168.240] X-EOPAttributedMessage: 0 X-Forefront-Antispam-Report: CIP:165.204.84.222;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(428002)(189002)(199003)(42186005)(97736004)(48376002)(47776003)(5003940100001)(5001770100001)(64706001)(15975445007)(50226001)(189998001)(5007970100001)(92566002)(36756003)(33646002)(87936001)(19580395003)(86362001)(229853001)(50466002)(105586002)(19580405001)(46102003)(106466001)(50986999)(5008740100001)(5004730100002)(101416001)(2004002);DIR:OUT;SFP:1101;SCL:1;SRVR:BY2PR12MB0709;H:atltwp02.amd.com;FPR:;SPF:None;PTR:InfoDomainNonexistent;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: 1;BY2PR12MB0709;2:0hV5jTuXSbjdxK55GsBLMxrMQyvEBaIkaThkuCmaqcoYz/ngrBKocF+wrw981SWwNYM/kaNqG16CTh/zm264EFFAqgg3hnBBNcPCdm+lEQFLSM4flHAB4TcC5xpL13DIr0atcEnXWUB60Jh5XiE/YTPV91wpgMvLsp3/VU2/o8g=;3:LTmGh/cj6xjfii39Yh7GU0lsKnYRUWpiz7m23Rne7ZmZQQXf3m04lIknM/b4xFOC6PdlCwzfgBNQTSXRdqdaWUoyx7Gl3GjFT2fp737ySZBVT0B8SXUVvghS934e7xjEmqtmQ7L2tCYVGadmyRi11DcwoZhpWxLQKyCqUN8jfT2ktGOxpabnPsGIzQ08OMpOKEuN2krVgwlxvDzzi+CdJnnLXrrT+2LMWSqA+mbHCfCzn3do03SO56iy7zPFEG7x;25:tN+7sS8+Bi6IEkdopSuf5uOtfbOGXyepAjT1LAzV091YimGXFS1hXbymblbeDiC9+fiWyeF++I7rVJ3oZWXp0brqevfMil0ckJxfb1+ZeXap9ecMtrgU+39AAqY+Umg3a+Q7PkuzYXyzM3XRmYN7b4IInMoEyCcCtMHuNTACPXg3lg6tHCg1lKgTR3b1P6lnsaCPhOjBQRHDdag7SVFvlNxp8es/K725KjrxorLBOfyBJQr9J2mvHe/+sXJJRSyfrmBXu489PXxBiqd+ymjSJg== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR12MB0709; X-Microsoft-Exchange-Diagnostics: 1;BY2PR12MB0709;20:29x6EB++0fOji+Lx+pksJEKk1hsDRLjRqcG/id1FzJSPXktewY3wcAC/GtM9d7zrH1aao56B3s2bQGAsYd1YIa6nQAFKC0y8SM/hmNOkITcWU2vdo/d9DcHhbr/ATdYz1KY3+IyfgnyZvheviA2OmzBh6dRgdl8Hvv3qRffXCdCzEbiJ0ioaBbsqSVcAMfNYM/xqw5g6RthUArkXPu3vJ8rBPG6ImWfz8je7Ijth58EQHENCsOdxe4Syb2feHg02avupEW+gy34BsePz0t2p7u1553v/IC42JgRxmfYFWJqmCuyZU9ZiNNkwBff96pCEStki2Ciy+h5SGO/zFMGR+APFf8cfT5x+UhqO7T6Asi3xgOXFYMZpkWu9EUqqjQNO5J0IaR23aN8k5wVY4EpyOpfocseIT5WKB0pamYU8qFXw8m3Ygujao3BVcc3yFf9mG3qmbLS9Z2F+53V34vuhbYwqZA0c2WpfYLDahz+GOVQLecSCXe4VwwfGAyUzp8W9;4:ooflJSYbjQYBL/mcPRCsp7MYKycDOJFQUBQumxThrupJSvkqyRzyCTOpgIIAdYlZAax8EZwaCyQaqH7I94khOgJDM6/jzVh9yFwm4bGzbV+8gcZMc0Lo3eAuTIifBHitsecYPNFMiXZ5XLUwe3Yv2X5oMI/Z7sL5/9x3c01lHSuM7KH0EwSkOJwA1Rutfome9nmD2hezd75UPv5NS2Ez+DQgQDC0OVRXkK7InKonmZRCKhTC9boitc0bF+m0bg5bsDzhQRtWOms5qLYt/CAWJFUjikikDtRFWrmOuCtcbnLjD/z1EcOWDEZCsBozb03d9vnr3JJuf/c8LE6dtdXHnkFvZtTGqN8Ggp8HpnRQHtg= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(8121501046)(5005006)(520078)(3002001);SRVR:BY2PR12MB0709;BCL:0;PCL:0;RULEID:;SRVR:BY2PR12MB0709; X-Forefront-PRVS: 07349BFAD2 X-Microsoft-Exchange-Diagnostics: 1;BY2PR12MB0709;23:xCPPYFR9jwZ+mh4kXNma/6XRDw7d25jt91MRsWrhD59/30h2f77xRv6dUCIF+xryaDZIL6UMYMIJ5XYzMEsLDna8aqWpPzWz6YK05L3SQwQ/0/tcCLqb5p5+Pu3LLDu5wR6gRpGFX1PsPsL1TetpWNWwgWDQvw1dT8xKy15zBFT4SU9faAeG9TSea12SUbz1rUgG6AkbImFjm/lE8TZRms5IGJVf4IToRSrox4nmkNyeM78VK8S5xllprt75jbnMMnUGgApX95wSWvsAvZiEEEb3a75aE+J56gxWlIW1p0P/2CuPeaphpxNgFzk+rm7YGhq6D6bXcM9m1e5+gumM8DifITgdxMIfxq0krSJQX5tJGcrWvSLqzGR6sH3nsoHghGxofU1fhUJniLeN2SY9/belIJJJf5Tvzms+Oo7WgoYoRWItzfE34oeaC93XlXchjKEs34q8iuxsOSFpHh36eZLvBWhMs8+D3KRu/PS6V9u9WhvR65wZbqeZ2CRH2DHpubLmlJuc4M5N0sQXvVx1rLn4QRFW7qe2iszO14+JcQKo9053QOmlt6El9sKHRDYtMeVSYM8WL3go1ciXwKwAOGRFLbO9tm0AHTjjqUiFfIt+uM1BoN95fClyPcX5FbmHPYhvf1mXpOmeyoJxiuiNIgFKIdxEZHkIVP8sakzRrDVcFLMAUv8zQIMU87HijMDUy7pRBGnlEL5hVR2CwGbURqi3+PscvczlcXygRgh7iyQoyDIHWD7WQFj2TIxJPGxcUnIzyuBbuN6wHOXizo53ediZjeYYWC7wI5vlQwVMH8uwMyXJrLbWIBVGeUdqnxls1MBeUS2Xu+b/GZ3dWEtdDtH3EGMrKkTXnILqDPDmGX7vwAMO/N+z29PlU+BFdJSByzJk8+eDQEozlZrMDpieBGZC7KnF59NOdaDlw5L3kGM= X-Microsoft-Exchange-Diagnostics: 1;BY2PR12MB0709;5:Rui8flylZRedIMOGq3mwBs2tcgLaDc5aXLJ0vWEV7P/P6Wj9c51kAdrtvAd21dZhGgcGmd5fjVpGOifSpdc/lettSA0CEV2PRlS12VHvuArldfsN592lK2l4KjrowiehHMmUe+zjhX5B6GrZQhfBSA==;24:DGLZZ8Knl4H2qvM3pGGdStQ6pUdrXzuekzZO/91iiMr5JlLhdf1QQad97YY4B8zNja3jz91rmYN+5vd06SHrDcwozdd00+J7jCT/G+5QEKU=;20:spXaO8jvNYXSxjfq/R7QbTVYYqjWOjdzSExKCBEhVIKiv5LuFai0lhx6uckXbr+jZL/DZZp1XhsKqwHw01I8hBy+bTLByM2zgrQXaStaU1NWM+Iq6LSnHUXHbQqp9RM1owJNBwfVQUQdOh50Djc5nKvoGaudGsNHGYl7vc9KR++jZpKyeChCQKtMdzm3oNDuFl7KkB8z8nnjQn5laWV1MC/D2UDvT1hBRLF3c+XUcXTo0uuyBjxUA9JlmBQLqS1U SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Oct 2015 19:25:01.0580 (UTC) X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.222];Helo=[atltwp02.amd.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR12MB0709 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for the AMD Seattle SoC EDAC driver. Signed-off-by: Brijesh Singh --- .../devicetree/bindings/edac/amd-seattle-edac.txt | 15 + drivers/edac/Kconfig | 6 + drivers/edac/Makefile | 1 + drivers/edac/seattle_edac.c | 306 +++++++++++++++++++++ 4 files changed, 328 insertions(+) create mode 100644 Documentation/devicetree/bindings/edac/amd-seattle-edac.txt create mode 100644 drivers/edac/seattle_edac.c diff --git a/Documentation/devicetree/bindings/edac/amd-seattle-edac.txt b/Documentation/devicetree/bindings/edac/amd-seattle-edac.txt new file mode 100644 index 0000000..a0354e8 --- /dev/null +++ b/Documentation/devicetree/bindings/edac/amd-seattle-edac.txt @@ -0,0 +1,15 @@ +* AMD Seattle SoC EDAC node + +EDAC node is defined to describe on-chip error detection and reporting. + +Required properties: +- compatible: Should be "amd,arm-seattle-edac" +- poll-delay-msec: Indicates how often the edac check callback should be called. + Time in msec. + +Example: + edac { + compatible = "amd,arm-seattle-edac"; + poll-delay-msec = <100>; + }; + diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index ef25000..d342335 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -390,4 +390,10 @@ config EDAC_XGENE Support for error detection and correction on the APM X-Gene family of SOCs. +config EDAC_SEATTLE + tristate "AMD Seattle EDAC" + depends on EDAC_MM_EDAC && ARCH_SEATTLE + help + Support for error detection and correction on the + AMD Seattle SOC. endif # EDAC diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index ae3c5f3..9e4f3ef 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o +obj-$(CONFIG_EDAC_SEATTLE) += seattle_edac.o diff --git a/drivers/edac/seattle_edac.c b/drivers/edac/seattle_edac.c new file mode 100644 index 0000000..78101aa --- /dev/null +++ b/drivers/edac/seattle_edac.c @@ -0,0 +1,306 @@ +/* + * AMD Seattle EDAC + * + * Copyright (c) 2015, Advanced Micro Devices + * Author: Brijesh Singh + * + * The driver polls CPUMERRSR_EL1 and L2MERRSR_EL1 registers to logs the + * non-fatal errors. Whereas the single bit and double bit ECC erros are + * handled by firmware. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "edac_core.h" + +#define EDAC_MOD_STR "seattle_edac" + +#define CPUMERRSR_EL1_INDEX(x) ((x) & 0x1ffff) +#define CPUMERRSR_EL1_BANK(x) (((x) >> 18) & 0x1f) +#define CPUMERRSR_EL1_RAMID(x) (((x) >> 24) & 0x7f) +#define CPUMERRSR_EL1_VALID(x) ((x) & (1 << 31)) +#define CPUMERRSR_EL1_REPEAT(x) (((x) >> 32) & 0x7f) +#define CPUMERRSR_EL1_OTHER(x) (((x) >> 40) & 0xff) +#define CPUMERRSR_EL1_FATAL(x) ((x) & (1UL << 63)) + +#define L2MERRSR_EL1_INDEX(x) ((x) & 0x1ffff) +#define L2MERRSR_EL1_CPUID(x) (((x) >> 18) & 0xf) +#define L2MERRSR_EL1_RAMID(x) (((x) >> 24) & 0x7f) +#define L2MERRSR_EL1_VALID(x) ((x) & (1 << 31)) +#define L2MERRSR_EL1_REPEAT(x) (((x) >> 32) & 0xff) +#define L2MERRSR_EL1_OTHER(x) (((x) >> 40) & 0xff) +#define L2MERRSR_EL1_FATAL(x) ((x) & (1UL << 63)) + +struct seattle_edac { + struct edac_device_ctl_info *edac_ctl; +}; + +static inline u64 read_cpumerrsr_el1(void) +{ + u64 val; + + asm volatile("mrs %0, s3_1_c15_c2_2" : "=r" (val)); + return val; +} + +static inline void write_cpumerrsr_el1(u64 val) +{ + asm volatile("msr s3_1_c15_c2_2, %0" :: "r" (val)); +} + +static inline u64 read_l2merrsr_el1(void) +{ + u64 val; + + asm volatile("mrs %0, s3_1_c15_c2_3" : "=r" (val)); + return val; +} + +static inline void write_l2merrsr_el1(u64 val) +{ + asm volatile("msr s3_1_c15_c2_3, %0" :: "r" (val)); +} + +static void check_l2merrsr_el1_error(struct edac_device_ctl_info *edac_ctl) +{ + int fatal; + int cpuid; + u64 val = read_l2merrsr_el1(); + + if (!L2MERRSR_EL1_VALID(val)) + return; + + fatal = L2MERRSR_EL1_FATAL(val); + cpuid = L2MERRSR_EL1_CPUID(val); + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "CPU%d detected %s error on L2 (L2MERRSR=%#llx)!\n", + smp_processor_id(), fatal ? "fatal" : "non-fatal", val); + + switch (L2MERRSR_EL1_RAMID(val)) { + case 0x10: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L2 Tag RAM cpu %d way %d\n", cpuid / 2, cpuid % 2); + break; + case 0x11: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L2 Data RAM cpu %d way %d\n", cpuid / 2, cpuid % 2); + break; + case 0x12: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L2 Snoop tag RAM cpu %d way %d\n", + cpuid / 2, cpuid % 2); + break; + case 0x14: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L2 Dirty RAM cpu %d way %d\n", + cpuid / 2, cpuid % 2); + break; + case 0x18: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L2 inclusion RAM cpu %d way %d\n", + cpuid / 2, cpuid % 2); + break; + default: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "unknown RAMID cpuid %d\n", cpuid); + break; + } + + edac_printk(KERN_CRIT, EDAC_MOD_STR, "Repeated error count: %d\n", + (int)L2MERRSR_EL1_REPEAT(val)); + edac_printk(KERN_CRIT, EDAC_MOD_STR, "Other error count: %d\n", + (int)L2MERRSR_EL1_OTHER(val)); + if (fatal) + edac_device_handle_ue(edac_ctl, smp_processor_id(), 1, + edac_ctl->name); + else + edac_device_handle_ce(edac_ctl, smp_processor_id(), 1, + edac_ctl->name); + write_l2merrsr_el1(0); +} + +static void check_cpumerrsr_el1_error(struct edac_device_ctl_info *edac_ctl) +{ + int fatal; + int bank; + u64 val = read_cpumerrsr_el1(); + + if (!CPUMERRSR_EL1_VALID(val)) + return; + + bank = CPUMERRSR_EL1_BANK(val); + fatal = CPUMERRSR_EL1_FATAL(val); + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "CPU%d detected %s error on L1 (CPUMERRSR=%#llx)!\n", + smp_processor_id(), fatal ? "fatal" : "non-fatal", val); + + switch (CPUMERRSR_EL1_RAMID(val)) { + case 0x0: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L1-I Tag RAM bank %d\n", bank); + break; + case 0x1: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L1-I Data RAM bank %d\n", bank); + break; + case 0x8: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L1-D Tag RAM bank %d\n", bank); + break; + case 0x9: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L1-D Data RAM bank %d\n", bank); + break; + case 0x18: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "L2 TLB RAM bank %d\n", bank); + break; + default: + edac_printk(KERN_CRIT, EDAC_MOD_STR, + "unknown ramid %d bank %d\n", + (int)CPUMERRSR_EL1_RAMID(val), bank); + break; + } + + edac_printk(KERN_CRIT, EDAC_MOD_STR, "Repeated error count: %d\n", + (int)CPUMERRSR_EL1_REPEAT(val)); + edac_printk(KERN_CRIT, EDAC_MOD_STR, "Other error count: %d\n", + (int)CPUMERRSR_EL1_OTHER(val)); + if (fatal) + edac_device_handle_ue(edac_ctl, smp_processor_id(), 1, + edac_ctl->name); + else + edac_device_handle_ce(edac_ctl, smp_processor_id(), 1, + edac_ctl->name); + write_cpumerrsr_el1(0); +} + +static void cpu_check_errors(void *args) +{ + struct edac_device_ctl_info *edev_ctl = args; + + check_cpumerrsr_el1_error(edev_ctl); + check_l2merrsr_el1_error(edev_ctl); +} + +static void edac_check_errors(struct edac_device_ctl_info *edev_ctl) +{ + int cpu; + + /* read L1 and L2 memory error syndrome register on possible CPU's */ + for_each_possible_cpu(cpu) + smp_call_function_single(cpu, cpu_check_errors, edev_ctl, 0); +} + +static int seattle_edac_probe(struct platform_device *pdev) +{ + int rc; + u32 poll_msec; + struct seattle_edac *drv; + struct device *dev = &pdev->dev; + + rc = of_property_read_u32(pdev->dev.of_node, "poll-delay-msec", + &poll_msec); + if (rc < 0) { + edac_printk(KERN_ERR, EDAC_MOD_STR, + "failed to get poll interval\n"); + return rc; + } + + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); + if (!drv) + return -ENOMEM; + + drv->edac_ctl = edac_device_alloc_ctl_info(0, "cpu", + num_possible_cpus(), "L", 2, + 1, NULL, 0, + edac_device_alloc_index()); + + drv->edac_ctl->poll_msec = poll_msec; + drv->edac_ctl->edac_check = edac_check_errors; + drv->edac_ctl->dev = dev; + drv->edac_ctl->mod_name = dev_name(dev); + drv->edac_ctl->dev_name = dev_name(dev); + drv->edac_ctl->ctl_name = "cpu_err"; + drv->edac_ctl->panic_on_ue = 1; + platform_set_drvdata(pdev, drv); + + rc = edac_device_add_device(drv->edac_ctl); + if (rc) + goto edac_alloc_failed; + + return 0; + +edac_alloc_failed: + edac_device_free_ctl_info(drv->edac_ctl); + return rc; +} + +static int seattle_edac_remove(struct platform_device *pdev) +{ + struct seattle_edac *drv = dev_get_drvdata(&pdev->dev); + struct edac_device_ctl_info *edac_ctl = drv->edac_ctl; + + edac_device_del_device(edac_ctl->dev); + edac_device_free_ctl_info(edac_ctl); + + return 0; +} + +static const struct of_device_id seattle_edac_of_match[] = { + { .compatible = "amd,arm-seattle-edac" }, + {}, +}; +MODULE_DEVICE_TABLE(of, seattle_edac_of_match); + +static struct platform_driver seattle_edac_driver = { + .probe = seattle_edac_probe, + .remove = seattle_edac_remove, + .driver = { + .name = "seattle-edac", + .of_match_table = seattle_edac_of_match, + }, +}; + +static int __init seattle_edac_init(void) +{ + int rc; + + /* we support poll method */ + edac_op_state = EDAC_OPSTATE_POLL; + + rc = platform_driver_register(&seattle_edac_driver); + if (rc) { + edac_printk(KERN_ERR, EDAC_MOD_STR, + "EDAC fails to register\n"); + return rc; + } + + return 0; +} +module_init(seattle_edac_init); + +static void __exit seattle_edac_exit(void) +{ + platform_driver_unregister(&seattle_edac_driver); +} +module_exit(seattle_edac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Brijesh Singh "); +MODULE_DESCRIPTION("AMD Seattle EDAC driver"); -- 1.9.1