From patchwork Sat Sep 10 19:56:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604616 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38C5AC6FA8E for ; Sat, 10 Sep 2022 19:57:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229811AbiIJT5S (ORCPT ); Sat, 10 Sep 2022 15:57:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40182 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229842AbiIJT5O (ORCPT ); Sat, 10 Sep 2022 15:57:14 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B68C143637; Sat, 10 Sep 2022 12:57:03 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 6B6DDDA5; Sat, 10 Sep 2022 23:00:52 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 6B6DDDA5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840052; bh=cB0N8dfWEL/C71MywOBEwKVvRrfKc3aPyovJSHro/iE=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=k2AVBGLOrHMiTU3eQrrdpeZmvMyZJmtapvhvRyguU5JyuoULxvGsvDGCFz7O12g8q ZSrNbt0Lx7uva2kb/oLFFwft574nnrR3wTGu5NETVXufblHr4RUJXRk1XcYkObiiLX rssHcDfSWAnuGxZEJcAM31/TvrMfwtmjMt7WjLPA= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:01 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , Krzysztof Kozlowski , Manish Narani CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Dinh Nguyen , James Morse , Robert Richter , Rob Herring , , , , , Krzysztof Kozlowski Subject: [PATCH v2 01/15] dt-bindings: memory: snps: Replace opencoded numbers with macros Date: Sat, 10 Sep 2022 22:56:45 +0300 Message-ID: <20220910195659.11843-2-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Xilinx ZynqMP DDRC-based example contains the opencoded numerical literals in the IRQ lines definition. It doesn't seem justified since the corresponding platform has well defined ARM GIC interface. Let's replace the numbers with the corresponding macros then. Signed-off-by: Serge Semin Acked-by: Rob Herring --- Changelog v2: - This is a new patch created on v2 based on the @Krzysztof' request not to have the opencoded numbers in the bindings example. (@Krzysztof) --- .../bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml b/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml index 9212dfe6e956..fb571d3d665d 100644 --- a/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml @@ -47,10 +47,13 @@ additionalProperties: false examples: - | + #include + memory-controller@fd070000 { compatible = "xlnx,zynqmp-ddrc-2.40a"; reg = <0xfd070000 0x30000>; + interrupt-parent = <&gic>; - interrupts = <0 112 4>; + interrupts = ; }; ... From patchwork Sat Sep 10 19:56:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604614 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01015C6FA82 for ; Sat, 10 Sep 2022 19:57:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230130AbiIJT5w (ORCPT ); Sat, 10 Sep 2022 15:57:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40526 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229989AbiIJT5X (ORCPT ); Sat, 10 Sep 2022 15:57:23 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 90A5245F7F; Sat, 10 Sep 2022 12:57:06 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 26BFFDA8; Sat, 10 Sep 2022 23:00:53 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 26BFFDA8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840053; bh=C1cHVya5vTRX4BQybgGAblj68eUfTg6JA+yP2FgH028=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=jFNNMjAMSit/oQmQ5gkfa1u0hXBIhLI/13fYl3wrKOEDQgeh6/fXXPA2oDFd2ES9y GHdpsp7WtcaZ3jlrktQwnOCDs+bq46Z0lXP7Eb3ZJyC942JMg0eqC8e5TDBA6RB+Fx KEin80j9t7fyxHBXMbeMeUr2c5Sqb3UHxczRufS4= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:02 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , Krzysztof Kozlowski , Manish Narani CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Dinh Nguyen , James Morse , Robert Richter , Rob Herring , , , , , Krzysztof Kozlowski Subject: [PATCH v2 02/15] dt-bindings: memory: snps: Extend schema with IRQs/resets/clocks props Date: Sat, 10 Sep 2022 22:56:46 +0300 Message-ID: <20220910195659.11843-3-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org First of all the DW uMCTL2 DDRC IP-core supports the individual IRQ lines for each standard event: ECC Corrected Error, ECC Uncorrected Error, ECC Address Protection, Scrubber-Done signal, DFI Parity/CRC Error. It's possible that the platform engineers merge them up in the IRQ controller level. So let's add both configuration support to the DT-schema. Secondly the DW uMCTL2 DDRC IP-core can have clock sources like APB reference clock, AXI-ports clock, main DDRC core reference clock and Scrubber low-power clock. In addition to that each clock domain can have a dedicated reset signal. Let's add the properties for at least the denoted clock sources and the corresponding reset controls. Note the IRQs and the phandles order is deliberately not fixed since some of the sources may be absent depending on the IP-core synthesize parameters and the particular platform setups. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- Changelog v2: - Replace "snps,ddrc-3.80a" compatible string with "snps,dw-umctl2-ddrc" in the example. - Move unrelated changes in to the dedicated patches. (@Krzysztof) - Use the IRQ macros in the example. (@Krzysztof) --- .../snps,dw-umctl2-ddrc.yaml | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml b/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml index fb571d3d665d..e68c4306025a 100644 --- a/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml @@ -33,11 +33,55 @@ properties: const: xlnx,zynqmp-ddrc-2.40a interrupts: - maxItems: 1 + description: + DW uMCTL2 DDRC IP-core provides individual IRQ signal for each event":" + ECC Corrected Error, ECC Uncorrected Error, ECC Address Protection, + Scrubber-Done signal, DFI Parity/CRC Error. Some platforms may have the + signals merged before they reach the IRQ controller or have some of them + absent in case if the corresponding feature is unavailable/disabled. + minItems: 1 + maxItems: 5 + + interrupt-names: + minItems: 1 + maxItems: 5 + oneOf: + - description: Common ECC CE/UE/Scrubber/DFI Errors IRQ + items: + - const: ecc + - description: Individual ECC CE/UE/Scrubber/DFI Errors IRQs + items: + enum: [ ecc_ce, ecc_ue, ecc_ap, ecc_sbr, dfi_e ] reg: maxItems: 1 + clocks: + description: + A standard set of the clock sources contains CSRs bus clock, AXI-ports + reference clock, DDRC core clock, Scrubber standalone clock + (synchronous to the DDRC clock). + minItems: 1 + maxItems: 4 + + clock-names: + minItems: 1 + maxItems: 4 + items: + enum: [ pclk, aclk, core, sbr ] + + resets: + description: + Each clock domain can have separate reset signal. + minItems: 1 + maxItems: 4 + + reset-names: + minItems: 1 + maxItems: 4 + items: + enum: [ prst, arst, core, sbr ] + required: - compatible - reg @@ -55,5 +99,20 @@ examples: interrupt-parent = <&gic>; interrupts = ; + interrupt-names = "ecc"; + }; + - | + #include + + memory-controller@3d400000 { + compatible = "snps,dw-umctl2-ddrc"; + reg = <0x3d400000 0x400000>; + + interrupts = <147 IRQ_TYPE_LEVEL_HIGH>, <148 IRQ_TYPE_LEVEL_HIGH>, + <149 IRQ_TYPE_LEVEL_HIGH>, <150 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "ecc_ce", "ecc_ue", "ecc_sbr", "dfi_e"; + + clocks = <&pclk>, <&aclk>, <&core_clk>, <&sbr_clk>; + clock-names = "pclk", "aclk", "core", "sbr"; }; ... From patchwork Sat Sep 10 19:56:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604615 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6FE7C6FA83 for ; Sat, 10 Sep 2022 19:57:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229986AbiIJT5X (ORCPT ); Sat, 10 Sep 2022 15:57:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40528 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229899AbiIJT5R (ORCPT ); Sat, 10 Sep 2022 15:57:17 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 515F44621D; Sat, 10 Sep 2022 12:57:12 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 1174DDBB; Sat, 10 Sep 2022 23:00:56 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 1174DDBB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840056; bh=bDc0hKH8QLJorEDXGsn27fQgVEEFeMzVEPd+KseCr0k=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=JYwUWicSDYi+Z9K7CRX72drdRRr+30bpUw8Tk3g38PDfOP/yDckXfznFy6V0j8JNk SdsOEUqczs9zsfgpMSu1xP1fC+0BXsRfr8rk31zXTRE4J5GVb06mVqgWIAY8mscpdl lo4WozLhl0yA4QXxiwKQFhHx6YiMd/bJaENfWx24= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:05 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , James Morse , Robert Richter CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Manish Narani , Dinh Nguyen , Rob Herring , Krzysztof Kozlowski , , , , Subject: [PATCH v2 06/15] EDAC/synopsys: Add optional ECC Scrub support Date: Sat, 10 Sep 2022 22:56:50 +0300 Message-ID: <20220910195659.11843-7-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org DW uMCTL2 DDRC ECC has a so called ECC Scrub feature in case if an single-bit error is detected. The scrub is executed as a new RMW operation to the location that resulted in a single-bit error thus fixing the ECC code preserved in the SDRAM. But that feature not only optional, but also runtime switchable. So there can be platforms with DW uMCTL2 DDRC not supporting hardware-base scrub. In those cases the single-bit errors will still be detected but won't be fixed until the next SDRAM write commands to the erroneous location. Since the ECC Scrub feature availability is detectable by means of the ECCCFG0.dis_scrub flag state we can use it to tune the MCI core up so one would automatically execute the platform-specific the platform-specific scrubbing to the affected SDRAM location. It's now possible to be done since the DW uMCTL2 DDRC driver supports the actual system address reported to the MCI core. The only thing left to do is to auto-detect the ECC Scrub feature availability and set the mem_ctl.info.scrub_mode mode with SCRUB_SW_SRC if the feature is unavailable. The rest will be done by the MCI core when the single-bit errors happen. Signed-off-by: Serge Semin --- drivers/edac/synopsys_edac.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index d5d82531719b..b36f7ec4a79e 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -32,6 +32,7 @@ #define SNPS_EDAC_MOD_VER "1" /* DDR capabilities */ +#define SNPS_CAP_ECC_SCRUB BIT(0) #define SNPS_CAP_ZYNQMP BIT(31) /* Synopsys uMCTL2 DDR controller registers that are relevant to ECC */ @@ -114,6 +115,7 @@ #define DDR_MSTR_MEM_LPDDR4 BIT(5) /* ECC CFG0 register definitions */ +#define ECC_CFG0_DIS_SCRUB BIT(4) #define ECC_CFG0_MODE_MASK GENMASK(2, 0) /* ECC status register definitions */ @@ -1008,6 +1010,10 @@ static int snps_get_ddrc_info(struct snps_edac_priv *priv) return -ENXIO; } + /* Assume HW-src scrub is always available if it isn't disabled */ + if (!(regval & ECC_CFG0_DIS_SCRUB)) + priv->info.caps |= SNPS_CAP_ECC_SCRUB; + /* Auto-detect the basic HIF/SDRAM bus parameters */ regval = readl(priv->baseaddr + DDR_MSTR_OFST); @@ -1484,8 +1490,14 @@ static struct mem_ctl_info *snps_mc_create(struct snps_edac_priv *priv) MEM_FLAG_DDR3 | MEM_FLAG_LPDDR3 | MEM_FLAG_DDR4 | MEM_FLAG_LPDDR4; mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; - mci->scrub_cap = SCRUB_FLAG_HW_SRC; - mci->scrub_mode = SCRUB_NONE; + + if (priv->info.caps & SNPS_CAP_ECC_SCRUB) { + mci->scrub_mode = SCRUB_HW_SRC; + mci->scrub_cap = SCRUB_FLAG_HW_SRC; + } else { + mci->scrub_mode = SCRUB_SW_SRC; + mci->scrub_cap = SCRUB_FLAG_SW_SRC; + } mci->edac_cap = EDAC_FLAG_SECDED; mci->ctl_name = "snps_umctl2_ddrc"; @@ -1578,6 +1590,8 @@ static int snps_ddrc_info_show(struct seq_file *s, void *data) seq_puts(s, "Caps:"); if (priv->info.caps) { + if (priv->info.caps & SNPS_CAP_ECC_SCRUB) + seq_puts(s, " +Scrub"); if (priv->info.caps & SNPS_CAP_ZYNQMP) seq_puts(s, " +ZynqMP"); } else { From patchwork Sat Sep 10 19:56:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604611 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCDF4C6FA89 for ; Sat, 10 Sep 2022 19:58:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230094AbiIJT6L (ORCPT ); Sat, 10 Sep 2022 15:58:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40478 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230091AbiIJT5e (ORCPT ); Sat, 10 Sep 2022 15:57:34 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3D11B474CA; Sat, 10 Sep 2022 12:57:18 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id E9F87DA5; Sat, 10 Sep 2022 23:00:57 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com E9F87DA5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840057; bh=0tsEL5BRHD+E3jNgz9wuLh2XsyldDO4cSjYtpKNv8qE=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=rfmvG1HZCA5I/0TFGlZLuwMR6PkOb0sEeeo6o6+Xz1mIYA+UGU1TdDySBVcvstibr QIoo3N1qSoupWgxGu2UfXxXB1tfZF3Y86M+wfP3eFVGvGFL8G5r7G5/OBbmalEd5Ia P0QLFWr1wVcmfkbduFFYoxiFNtzWO5WUDIiLM8g0= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:07 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , James Morse , Robert Richter CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Manish Narani , Dinh Nguyen , Rob Herring , Krzysztof Kozlowski , , , , Subject: [PATCH v2 09/15] EDAC/synopsys: Split up ECC UE/CE IRQs handler Date: Sat, 10 Sep 2022 22:56:53 +0300 Message-ID: <20220910195659.11843-10-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org DW uMCTL2 DDRC IP-core doesn't have common IRQ line. Instead it provides individual IRQ output signals for each controller event like: corrected error, uncorrected error, DFI parity error, address protection, scrubber done, and so on. So the common IRQ handler implemented in the Synopsys EDAC driver isn't device-specific but is a particular platform specific. Obviously it won't be suitable for the generic devices which are added to the platforms with the original individual IRQs as it has happened in our case. So let's split up the common IRQ handler into two ones handling ECC corrected and uncorrected errors. It won't be that hard since both sub-methods it calls are already logically divided into two CE/UE parts. What we need to do is to move these parts into the dedicated methods and redefine the local variables a bit. The new methods will be simply called from the common IRQs handler if one is utilized on the particular platform. Otherwise each new IRQ handler will be called on particular interrupt request (the IRQ handlers registration will be added a bit later). Note we now can discard the snps_ecc_status structure as unneeded since the error data is collected and reported now within a single method. Signed-off-by: Serge Semin --- drivers/edac/synopsys_edac.c | 272 +++++++++++++++++------------------ 1 file changed, 135 insertions(+), 137 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 1df5be2af1de..e5359ff2ed25 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -143,7 +143,6 @@ #define DDR_QOS_IRQ_STAT_OFST 0x20200 #define DDR_QOSUE_MASK BIT(2) #define DDR_QOSCE_MASK BIT(1) -#define ECC_CE_UE_INTR_MASK (DDR_QOSUE_MASK | DDR_QOSCE_MASK) #define DDR_QOS_IRQ_EN_OFST 0x20208 #define DDR_QOS_IRQ_DB_OFST 0x2020C @@ -372,31 +371,19 @@ struct snps_sdram_addr { /** * struct snps_ecc_error_info - ECC error log information. * @sdram: SDRAM address. + * @ecnt: Number of detected errors. * @bitpos: Bit position. * @data: Data causing the error. * @syndrome: Erroneous data syndrome. */ struct snps_ecc_error_info { struct snps_sdram_addr sdram; + u16 ecnt; u32 bitpos; u64 data; u32 syndrome; }; -/** - * struct snps_ecc_status - ECC status information to report. - * @ce_cnt: Correctable error count. - * @ue_cnt: Uncorrectable error count. - * @ceinfo: Correctable error log information. - * @ueinfo: Uncorrectable error log information. - */ -struct snps_ecc_status { - u32 ce_cnt; - u32 ue_cnt; - struct snps_ecc_error_info ceinfo; - struct snps_ecc_error_info ueinfo; -}; - /** * struct snps_edac_priv - DDR memory controller private data. * @info: DDR controller config info. @@ -406,7 +393,6 @@ struct snps_ecc_status { * @baseaddr: Base address of the DDR controller. * @lock: Concurrent CSRs access lock. * @message: Buffer for framing the event specific info. - * @stat: ECC status information. */ struct snps_edac_priv { struct snps_ddrc_info info; @@ -416,7 +402,6 @@ struct snps_edac_priv { void __iomem *baseaddr; spinlock_t lock; char message[SNPS_EDAC_MSG_SIZE]; - struct snps_ecc_status stat; }; /** @@ -688,130 +673,178 @@ static inline u32 snps_get_bitpos(u32 bitnum, enum snps_dq_width dq_width) } /** - * snps_get_error_info - Get the current ECC error info. - * @priv: DDR memory controller private instance data. + * snps_ce_irq_handler - Corrected error interrupt handler. + * @irq: IRQ number. + * @dev_id: Device ID. * - * Return: one if there is no error otherwise returns zero. + * Return: IRQ_NONE, if interrupt not set or IRQ_HANDLED otherwise. */ -static int snps_get_error_info(struct snps_edac_priv *priv) +static irqreturn_t snps_ce_irq_handler(int irq, void *dev_id) { - struct snps_ecc_status *p; - u32 regval, clearval; + struct mem_ctl_info *mci = dev_id; + struct snps_edac_priv *priv = mci->pvt_info; + struct snps_ecc_error_info einfo; unsigned long flags; - void __iomem *base; + u32 qosval, regval; + dma_addr_t sys; - base = priv->baseaddr; - p = &priv->stat; + /* Make sure IRQ is caused by a corrected ECC error */ + if (priv->info.caps & SNPS_CAP_ZYNQMP) { + qosval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); + if (!(qosval & DDR_QOSCE_MASK)) + return IRQ_NONE; - regval = readl(base + ECC_STAT_OFST); - if (!regval) - return 1; + qosval &= DDR_QOSCE_MASK; + } - p->ceinfo.bitpos = FIELD_GET(ECC_STAT_BITNUM_MASK, regval); + regval = readl(priv->baseaddr + ECC_STAT_OFST); + if (!FIELD_GET(ECC_STAT_CE_MASK, regval)) + return IRQ_NONE; - regval = readl(base + ECC_ERRCNT_OFST); - p->ce_cnt = FIELD_GET(ECC_ERRCNT_CECNT_MASK, regval); - p->ue_cnt = FIELD_GET(ECC_ERRCNT_UECNT_MASK, regval); - if (!p->ce_cnt) - goto ue_err; + /* Read error info like bit position, SDRAM address, data, syndrome */ + einfo.bitpos = FIELD_GET(ECC_STAT_BITNUM_MASK, regval); + einfo.bitpos = snps_get_bitpos(einfo.bitpos, priv->info.dq_width); - p->ceinfo.bitpos = snps_get_bitpos(p->ceinfo.bitpos, priv->info.dq_width); + regval = readl(priv->baseaddr + ECC_ERRCNT_OFST); + einfo.ecnt = FIELD_GET(ECC_ERRCNT_CECNT_MASK, regval); - regval = readl(base + ECC_CEADDR0_OFST); - p->ceinfo.sdram.rank = FIELD_GET(ECC_CEADDR0_RANK_MASK, regval); - p->ceinfo.sdram.row = FIELD_GET(ECC_CEADDR0_ROW_MASK, regval); + regval = readl(priv->baseaddr + ECC_CEADDR0_OFST); + einfo.sdram.rank = FIELD_GET(ECC_CEADDR0_RANK_MASK, regval); + einfo.sdram.row = FIELD_GET(ECC_CEADDR0_ROW_MASK, regval); - regval = readl(base + ECC_CEADDR1_OFST); - p->ceinfo.sdram.bankgrp = FIELD_GET(ECC_CEADDR1_BANKGRP_MASK, regval); - p->ceinfo.sdram.bank = FIELD_GET(ECC_CEADDR1_BANK_MASK, regval); - p->ceinfo.sdram.col = FIELD_GET(ECC_CEADDR1_COL_MASK, regval); + regval = readl(priv->baseaddr + ECC_CEADDR1_OFST); + einfo.sdram.bankgrp = FIELD_GET(ECC_CEADDR1_BANKGRP_MASK, regval); + einfo.sdram.bank = FIELD_GET(ECC_CEADDR1_BANK_MASK, regval); + einfo.sdram.col = FIELD_GET(ECC_CEADDR1_COL_MASK, regval); - p->ceinfo.data = readl(base + ECC_CSYND0_OFST); + einfo.data = readl(priv->baseaddr + ECC_CSYND0_OFST); if (priv->info.dq_width == SNPS_DQ_64) - p->ceinfo.data |= (u64)readl(base + ECC_CSYND1_OFST) << 32; - - p->ceinfo.syndrome = readl(base + ECC_CSYND2_OFST); + einfo.data |= (u64)readl(priv->baseaddr + ECC_CSYND1_OFST) << 32; -ue_err: - if (!p->ue_cnt) - goto out; + einfo.syndrome = readl(priv->baseaddr + ECC_CSYND2_OFST); - regval = readl(base + ECC_UEADDR0_OFST); - p->ueinfo.sdram.rank = FIELD_GET(ECC_CEADDR0_RANK_MASK, regval); - p->ueinfo.sdram.row = FIELD_GET(ECC_CEADDR0_ROW_MASK, regval); + /* Report the detected errors with the corresponding sys address */ + snps_map_sdram_to_sys(priv, &einfo.sdram, &sys); - regval = readl(base + ECC_UEADDR1_OFST); - p->ueinfo.sdram.bankgrp = FIELD_GET(ECC_CEADDR1_BANKGRP_MASK, regval); - p->ueinfo.sdram.bank = FIELD_GET(ECC_CEADDR1_BANK_MASK, regval); - p->ueinfo.sdram.col = FIELD_GET(ECC_CEADDR1_COL_MASK, regval); + snprintf(priv->message, SNPS_EDAC_MSG_SIZE, + "Row %hu Col %hu Bank %hhu Bank Group %hhu Rank %hhu Bit %d Data 0x%08llx", + einfo.sdram.row, einfo.sdram.col, einfo.sdram.bank, + einfo.sdram.bankgrp, einfo.sdram.rank, + einfo.bitpos, einfo.data); - p->ueinfo.data = readl(base + ECC_UESYND0_OFST); - if (priv->info.dq_width == SNPS_DQ_64) - p->ueinfo.data |= (u64)readl(base + ECC_UESYND1_OFST) << 32; - - p->ueinfo.syndrome = readl(base + ECC_UESYND2_OFST); + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, einfo.ecnt, + PHYS_PFN(sys), offset_in_page(sys), + einfo.syndrome, einfo.sdram.rank, 0, -1, + priv->message, ""); -out: + /* Make sure the CE IRQ status is cleared */ spin_lock_irqsave(&priv->lock, flags); - clearval = readl(base + ECC_CLR_OFST) | - ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT | - ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; - writel(clearval, base + ECC_CLR_OFST); + regval = readl(priv->baseaddr + ECC_CLR_OFST) | + ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; + writel(regval, priv->baseaddr + ECC_CLR_OFST); spin_unlock_irqrestore(&priv->lock, flags); - return 0; + if (priv->info.caps & SNPS_CAP_ZYNQMP) + writel(qosval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); + + return IRQ_HANDLED; } /** - * snps_handle_error - Handle Correctable and Uncorrectable errors. - * @mci: EDAC memory controller instance. - * @p: Synopsys ECC status structure. + * snps_ue_irq_handler - Uncorrected error interrupt handler. + * @irq: IRQ number. + * @dev_id: Device ID. * - * Handles ECC correctable and uncorrectable errors. + * Return: IRQ_NONE, if interrupt not set or IRQ_HANDLED otherwise. */ -static void snps_handle_error(struct mem_ctl_info *mci, struct snps_ecc_status *p) +static irqreturn_t snps_ue_irq_handler(int irq, void *dev_id) { + struct mem_ctl_info *mci = dev_id; struct snps_edac_priv *priv = mci->pvt_info; - struct snps_ecc_error_info *pinf; + struct snps_ecc_error_info einfo; + unsigned long flags; + u32 qosval, regval; dma_addr_t sys; - if (p->ce_cnt) { - pinf = &p->ceinfo; + /* Make sure IRQ is caused by an uncorrected ECC error */ + if (priv->info.caps & SNPS_CAP_ZYNQMP) { + qosval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); + if (!(regval & DDR_QOSUE_MASK)) + return IRQ_NONE; + + qosval &= DDR_QOSUE_MASK; + } - snprintf(priv->message, SNPS_EDAC_MSG_SIZE, - "Row %hu Col %hu Bank %hhu Bank Group %hhu Rank %hhu Bit %d Data 0x%08llx", - pinf->sdram.row, pinf->sdram.col, pinf->sdram.bank, - pinf->sdram.bankgrp, pinf->sdram.rank, - pinf->bitpos, pinf->data); + regval = readl(priv->baseaddr + ECC_STAT_OFST); + if (!FIELD_GET(ECC_STAT_UE_MASK, regval)) + return IRQ_NONE; - snps_map_sdram_to_sys(priv, &pinf->sdram, &sys); + /* Read error info like SDRAM address, data and syndrome */ + regval = readl(priv->baseaddr + ECC_ERRCNT_OFST); + einfo.ecnt = FIELD_GET(ECC_ERRCNT_UECNT_MASK, regval); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, p->ce_cnt, - PHYS_PFN(sys), offset_in_page(sys), - pinf->syndrome, pinf->sdram.rank, 0, -1, - priv->message, ""); - } + regval = readl(priv->baseaddr + ECC_UEADDR0_OFST); + einfo.sdram.rank = FIELD_GET(ECC_CEADDR0_RANK_MASK, regval); + einfo.sdram.row = FIELD_GET(ECC_CEADDR0_ROW_MASK, regval); - if (p->ue_cnt) { - pinf = &p->ueinfo; + regval = readl(priv->baseaddr + ECC_UEADDR1_OFST); + einfo.sdram.bankgrp = FIELD_GET(ECC_CEADDR1_BANKGRP_MASK, regval); + einfo.sdram.bank = FIELD_GET(ECC_CEADDR1_BANK_MASK, regval); + einfo.sdram.col = FIELD_GET(ECC_CEADDR1_COL_MASK, regval); - snprintf(priv->message, SNPS_EDAC_MSG_SIZE, - "Row %hu Col %hu Bank %hhu Bank Group %hhu Rank %hhu Data 0x%08llx", - pinf->sdram.row, pinf->sdram.col, pinf->sdram.bank, - pinf->sdram.bankgrp, pinf->sdram.rank, - pinf->data); + einfo.data = readl(priv->baseaddr + ECC_UESYND0_OFST); + if (priv->info.dq_width == SNPS_DQ_64) + einfo.data |= (u64)readl(priv->baseaddr + ECC_UESYND1_OFST) << 32; - snps_map_sdram_to_sys(priv, &pinf->sdram, &sys); + einfo.syndrome = readl(priv->baseaddr + ECC_UESYND2_OFST); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, p->ue_cnt, - PHYS_PFN(sys), offset_in_page(sys), - pinf->syndrome, pinf->sdram.rank, 0, -1, - priv->message, ""); - } + /* Report the detected errors with the corresponding sys address */ + snps_map_sdram_to_sys(priv, &einfo.sdram, &sys); + + snprintf(priv->message, SNPS_EDAC_MSG_SIZE, + "Row %hu Col %hu Bank %hhu Bank Group %hhu Rank %hhu Data 0x%08llx", + einfo.sdram.row, einfo.sdram.col, einfo.sdram.bank, + einfo.sdram.bankgrp, einfo.sdram.rank, + einfo.data); + + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, einfo.ecnt, + PHYS_PFN(sys), offset_in_page(sys), + einfo.syndrome, einfo.sdram.rank, 0, -1, + priv->message, ""); + + /* Make sure the UE IRQ status is cleared */ + spin_lock_irqsave(&priv->lock, flags); + + regval = readl(priv->baseaddr + ECC_CLR_OFST) | + ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + writel(regval, priv->baseaddr + ECC_CLR_OFST); - memset(p, 0, sizeof(*p)); + spin_unlock_irqrestore(&priv->lock, flags); + + if (priv->info.caps & SNPS_CAP_ZYNQMP) + writel(qosval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); + + return IRQ_HANDLED; +} + +/** + * snps_com_irq_handler - Interrupt IRQ signal handler. + * @irq: IRQ number. + * @dev_id: Device ID. + * + * Return: IRQ_NONE, if interrupts not set or IRQ_HANDLED otherwise. + */ +static irqreturn_t snps_com_irq_handler(int irq, void *dev_id) +{ + irqreturn_t rc = IRQ_NONE; + + rc |= snps_ce_irq_handler(irq, dev_id); + + rc |= snps_ue_irq_handler(irq, dev_id); + + return rc; } static void snps_enable_irq(struct snps_edac_priv *priv) @@ -854,41 +887,6 @@ static void snps_disable_irq(struct snps_edac_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -/** - * snps_irq_handler - Interrupt Handler for ECC interrupts. - * @irq: IRQ number. - * @dev_id: Device ID. - * - * Return: IRQ_NONE, if interrupt not set or IRQ_HANDLED otherwise. - */ -static irqreturn_t snps_irq_handler(int irq, void *dev_id) -{ - struct mem_ctl_info *mci = dev_id; - struct snps_edac_priv *priv; - int status, regval; - - priv = mci->pvt_info; - - if (priv->info.caps & SNPS_CAP_ZYNQMP) { - regval = readl(priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); - regval &= (DDR_QOSCE_MASK | DDR_QOSUE_MASK); - if (!(regval & ECC_CE_UE_INTR_MASK)) - return IRQ_NONE; - } - - status = snps_get_error_info(priv); - if (status) - return IRQ_NONE; - - snps_handle_error(mci, &priv->stat); - - - if (priv->info.caps & SNPS_CAP_ZYNQMP) - writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); - - return IRQ_HANDLED; -} - /** * snps_create_data - Create private data. * @pdev: platform device. @@ -1538,7 +1536,7 @@ static int snps_setup_irq(struct mem_ctl_info *mci) return irq; } - ret = devm_request_irq(&priv->pdev->dev, irq, snps_irq_handler, + ret = devm_request_irq(&priv->pdev->dev, irq, snps_com_irq_handler, 0, dev_name(&priv->pdev->dev), mci); if (ret < 0) { edac_printk(KERN_ERR, EDAC_MC, "Failed to request IRQ\n"); From patchwork Sat Sep 10 19:56:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604613 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9A92C6FA83 for ; Sat, 10 Sep 2022 19:58:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229815AbiIJT6B (ORCPT ); Sat, 10 Sep 2022 15:58:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41020 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229789AbiIJT5Z (ORCPT ); Sat, 10 Sep 2022 15:57:25 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0C19047BB0; Sat, 10 Sep 2022 12:57:19 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 96A00DBD; Sat, 10 Sep 2022 23:00:58 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 96A00DBD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840058; bh=evl0QMbGUuK/VXmVFTFt7CDJBznWz4C4rkPe+VRXbvI=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=Uweo5280VyjXFAZ3PggU/9ogmf6kTDN4pgivwpaQO/gOUoUsS2UT4Qa8nyTRxQSRe VwXVhhb0SiBhpT/Wj3yYFD68W4Ttt/Rw5yn4mEn0dz7zLEpfUNGYCnjrlbrexxpcp3 TWu6bZkuql3lYwvYOqafARTeFJTn1ebO6dMY8mdM= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:07 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , James Morse , Robert Richter CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Manish Narani , Dinh Nguyen , Rob Herring , Krzysztof Kozlowski , , , , Subject: [PATCH v2 10/15] EDAC/synopsys: Add individual named ECC IRQs support Date: Sat, 10 Sep 2022 22:56:54 +0300 Message-ID: <20220910195659.11843-11-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Currently the DW uMCTL2 DDRC EDAC driver supports a common unnamed IRQ only. It isn't suitable for our platform which has the individual IRQ lines for each DDRC event (ECC UE, ECC CE, DFI parity error, Scrubber done, etc). Moreover the DW uMCTL2 DDRC IP-core doesn't have an option to be configured with a common interrupts output line. So in order to have the generic DW uMCTL2 DDR controller and our platform supported by the driver we need to add the individual, per DDRC event, IRQs request support. There is not much to do really since the common IRQs handler has already been split up into the sub-handlers. So the only thing we need to do is first try to request the individual IRQs, if failed then fallback to the common IRQ. The IRQ names are used in accordance with the DW uMCTL2 DDRC DT-bindings. Signed-off-by: Serge Semin --- drivers/edac/synopsys_edac.c | 91 ++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 10 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index e5359ff2ed25..6a47e53deab5 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -1524,25 +1524,96 @@ static void snps_mc_free(struct mem_ctl_info *mci) edac_mc_free(mci); } -static int snps_setup_irq(struct mem_ctl_info *mci) +/** + * snps_request_ind_irq - Request individual DDRC IRQs. + * @mci: EDAC memory controller instance. + * + * Return: 0 if the IRQs were successfully requested, 1 if the individual IRQs + * are unavailable, otherwise negative errno. + */ +static int snps_request_ind_irq(struct mem_ctl_info *mci) { struct snps_edac_priv *priv = mci->pvt_info; - int ret, irq; + struct device *dev = &priv->pdev->dev; + int rc, irq; - irq = platform_get_irq(priv->pdev, 0); - if (irq < 0) { - edac_printk(KERN_ERR, EDAC_MC, - "No IRQ %d in DT\n", irq); + irq = platform_get_irq_byname_optional(priv->pdev, "ecc_ce"); + if (irq == -ENXIO) + return 1; + if (irq < 0) + return irq; + + rc = devm_request_irq(dev, irq, snps_ce_irq_handler, 0, "ecc_ce", mci); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, "Failed to request ECC CE IRQ\n"); + return rc; + } + + irq = platform_get_irq_byname(priv->pdev, "ecc_ue"); + if (irq < 0) return irq; + + rc = devm_request_irq(dev, irq, snps_ue_irq_handler, 0, "ecc_ue", mci); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, "Failed to request ECC UE IRQ\n"); + return rc; + } + + return 0; +} + +/** + * snps_request_com_irq - Request common DDRC IRQ. + * @mci: EDAC memory controller instance. + * + * It first attempts to get the named IRQ. If failed the method fallbacks + * to first available one. + * + * Return: 0 if the IRQ was successfully requested otherwise negative errno. + */ +static int snps_request_com_irq(struct mem_ctl_info *mci) +{ + struct snps_edac_priv *priv = mci->pvt_info; + struct device *dev = &priv->pdev->dev; + int rc, irq; + + irq = platform_get_irq_byname_optional(priv->pdev, "ecc"); + if (irq < 0) { + irq = platform_get_irq(priv->pdev, 0); + if (irq < 0) + return irq; } - ret = devm_request_irq(&priv->pdev->dev, irq, snps_com_irq_handler, - 0, dev_name(&priv->pdev->dev), mci); - if (ret < 0) { + rc = devm_request_irq(dev, irq, snps_com_irq_handler, 0, "ecc", mci); + if (rc) { edac_printk(KERN_ERR, EDAC_MC, "Failed to request IRQ\n"); - return ret; + return rc; } + return 0; +} + +/** + * snps_setup_irq - Request and enable DDRC IRQs. + * @mci: EDAC memory controller instance. + * + * It first tries to get and request individual IRQs. If failed the method + * fallbacks to the common IRQ line case. The IRQs will be enabled only if + * some of these requests have been successful. + * + * Return: 0 if IRQs were successfully setup otherwise negative errno. + */ +static int snps_setup_irq(struct mem_ctl_info *mci) +{ + struct snps_edac_priv *priv = mci->pvt_info; + int rc; + + rc = snps_request_ind_irq(mci); + if (rc > 0) + rc = snps_request_com_irq(mci); + if (rc) + return rc; + snps_enable_irq(priv); return 0; From patchwork Sat Sep 10 19:56:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604612 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9D14C6FA82 for ; Sat, 10 Sep 2022 19:58:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229437AbiIJT6G (ORCPT ); Sat, 10 Sep 2022 15:58:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229831AbiIJT5a (ORCPT ); Sat, 10 Sep 2022 15:57:30 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 2738C476ED; Sat, 10 Sep 2022 12:57:25 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id D985ADBF; Sat, 10 Sep 2022 23:00:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com D985ADBF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840059; bh=T3CV91djzYazoRWrEPNnzkdz0BKd0JHDUI0FBn6UuwM=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=qibWuN65MgBVxy1h7ZUQ9ssH9U/dk6eHcoTepjtiDassDrvkIxRcsRWMeUc1kBycJ gUYk+B1TQpUrfMIqzyXcDi4mEAgfp9bxJzKwvGIk+01YX/SNlTau+ywxOOihi0P/jF ZXYOTNS7vsNvLTvXOlVDlCu6zc8QeoVgm+Ifpt/c= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:09 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , James Morse , Robert Richter CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Manish Narani , Dinh Nguyen , Rob Herring , Krzysztof Kozlowski , , , , Subject: [PATCH v2 12/15] EDAC/synopsys: Add reference clocks support Date: Sat, 10 Sep 2022 22:56:56 +0300 Message-ID: <20220910195659.11843-13-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Currently the driver doesn't support any clock-related resources request and handling, fairly assuming that all of them are supposed to be enabled anyway in order for the system to work correctly. It's true for the Core and AXI Ports reference clocks, but the CSR (APB) and Scrubber clocks might still be disabled in case if the system firmware doesn't imply any other software touching the DDR controller internals. Since the DW uMCTL2 DDRC driver does access the controller registers at the very least we need to make sure the APB clock is enabled. Let's add the reference clocks support then. First of all the driver will request all the clocks possibly defined for the controller (Core, AXI, APB and Scrubber). Secondly the APB clock will be enabled/disabled only since the Scrubber is currently unsupported by the driver, and the Core and AXI clocks feed the critical system parts so we need to avoid touching them with a risk to de-stabilize the system memory. Please note the clocks connection IDs have been chosen in accordance with the DT-bindings. Signed-off-by: Serge Semin --- drivers/edac/synopsys_edac.c | 101 +++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 3 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index 8d8952826bce..4b204b2050d4 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -301,6 +302,25 @@ enum snps_ecc_mode { SNPS_ECC_ADVX4X8 = 5, }; +/** + * enum snps_ref_clk - DW uMCTL2 DDR controller clocks. + * @SNPS_CSR_CLK: CSR/APB interface clock. + * @SNPS_AXI_CLK: AXI (AHB) Port reference clock. + * @SNPS_CORE_CLK: DDR controller (including DFI) clock. SDRAM clock + * matches runs with this freq in 1:1 ratio mode and + * with twice of this freq in case of 1:2 ratio mode. + * @SNPS_SBR_CLK: Scrubber port reference clock (synchronous to + * the core clock). + * @SNPS_MAX_NCLK: Total number of clocks. + */ +enum snps_ref_clk { + SNPS_CSR_CLK, + SNPS_AXI_CLK, + SNPS_CORE_CLK, + SNPS_SBR_CLK, + SNPS_MAX_NCLK +}; + /** * struct snps_ddrc_info - DDR controller platform parameters. * @caps: DDR controller capabilities. @@ -405,6 +425,7 @@ struct snps_ecc_error_info { * @pdev: Platform device. * @baseaddr: Base address of the DDR controller. * @lock: Concurrent CSRs access lock. + * @clks: Controller reference clocks. * @message: Buffer for framing the event specific info. */ struct snps_edac_priv { @@ -414,6 +435,7 @@ struct snps_edac_priv { struct platform_device *pdev; void __iomem *baseaddr; spinlock_t lock; + struct clk_bulk_data clks[SNPS_MAX_NCLK]; char message[SNPS_EDAC_MSG_SIZE]; }; @@ -974,6 +996,60 @@ static struct snps_edac_priv *snps_create_data(struct platform_device *pdev) return priv; } +/** + * snps_get_res - Get platform device resources. + * @priv: DDR memory controller private instance data. + * + * It's supposed to request all the controller resources available for the + * particular platform and enable all the required for the driver normal + * work. Note only the CSR and Scrubber clocks are supposed to be switched + * on/off by the driver. + * + * Return: negative errno if failed to get the resources, otherwise - zero. + */ +static int snps_get_res(struct snps_edac_priv *priv) +{ + const char * const ids[] = { + [SNPS_CSR_CLK] = "pclk", + [SNPS_AXI_CLK] = "aclk", + [SNPS_CORE_CLK] = "core", + [SNPS_SBR_CLK] = "sbr", + }; + int i, rc; + + for (i = 0; i < SNPS_MAX_NCLK; i++) + priv->clks[i].id = ids[i]; + + rc = devm_clk_bulk_get_optional(&priv->pdev->dev, SNPS_MAX_NCLK, + priv->clks); + if (rc) { + edac_printk(KERN_INFO, EDAC_MC, "Failed to get ref clocks\n"); + return rc; + } + + /* + * Don't touch the Core and AXI clocks since they are critical for the + * stable system functioning and are supposed to have been enabled + * anyway. + */ + rc = clk_prepare_enable(priv->clks[SNPS_CSR_CLK].clk); + if (rc) { + edac_printk(KERN_INFO, EDAC_MC, "Couldn't enable CSR clock\n"); + return rc; + } + + return 0; +} + +/** + * snps_put_res - Put platform device resources. + * @priv: DDR memory controller private instance data. + */ +static void snps_put_res(struct snps_edac_priv *priv) +{ + clk_disable_unprepare(priv->clks[SNPS_CSR_CLK].clk); +} + /* * zynqmp_init_plat - ZynqMP-specific platform initialization. * @priv: DDR memory controller private data. @@ -1707,9 +1783,17 @@ static int snps_ddrc_info_show(struct seq_file *s, void *data) { struct mem_ctl_info *mci = s->private; struct snps_edac_priv *priv = mci->pvt_info; + unsigned long rate; seq_printf(s, "SDRAM: %s\n", edac_mem_types[priv->info.sdram_mode]); + rate = clk_get_rate(priv->clks[SNPS_CORE_CLK].clk); + if (rate) { + rate = rate / HZ_PER_MHZ; + seq_printf(s, "Clock: Core %luMHz SDRAM %luMHz\n", + rate, priv->info.freq_ratio * rate); + } + seq_printf(s, "DQ bus: %u/%s\n", (BITS_PER_BYTE << priv->info.dq_width), priv->info.dq_mode == SNPS_DQ_FULL ? "Full" : priv->info.dq_mode == SNPS_DQ_HALF ? "Half" : @@ -2018,15 +2102,21 @@ static int snps_mc_probe(struct platform_device *pdev) if (IS_ERR(priv)) return PTR_ERR(priv); - rc = snps_get_ddrc_info(priv); + rc = snps_get_res(priv); if (rc) return rc; + rc = snps_get_ddrc_info(priv); + if (rc) + goto put_res; + snps_get_addr_map(priv); mci = snps_mc_create(priv); - if (IS_ERR(mci)) - return PTR_ERR(mci); + if (IS_ERR(mci)) { + rc = PTR_ERR(mci); + goto put_res; + } rc = snps_setup_irq(mci); if (rc) @@ -2046,6 +2136,9 @@ static int snps_mc_probe(struct platform_device *pdev) free_edac_mc: snps_mc_free(mci); +put_res: + snps_put_res(priv); + return rc; } @@ -2066,6 +2159,8 @@ static int snps_mc_remove(struct platform_device *pdev) snps_mc_free(mci); + snps_put_res(priv); + return 0; } From patchwork Sat Sep 10 19:56:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 604610 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1A470C6FA8B for ; Sat, 10 Sep 2022 19:58:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230114AbiIJT6V (ORCPT ); Sat, 10 Sep 2022 15:58:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40534 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229889AbiIJT5o (ORCPT ); Sat, 10 Sep 2022 15:57:44 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id F410548C99; Sat, 10 Sep 2022 12:57:28 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 2EE52DC1; Sat, 10 Sep 2022 23:01:01 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 2EE52DC1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1662840061; bh=RwEiigR8bgbuCrmmwLrEzmaj33P5Q6XpCRsItf5uEUE=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=m7QJkD7PucRz4Hcz34Srw77lHqb/tsBOOv2kbVsysn5y2CvCCe2SPGA8mIUBOz4Gr 9NUxlwipX1/aZwQwa/7EIp4VUlQjVp3xldxCYTPRw3Z1aE1riY8ADbplhTIVdjE1Wl +zXgeQ2eFrS9LpKRYtJtXQmCHTTlbWrp3wzkBIk4= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Sat, 10 Sep 2022 22:57:10 +0300 From: Serge Semin To: Rob Herring , Krzysztof Kozlowski , Michal Simek , Borislav Petkov , Mauro Carvalho Chehab , Tony Luck , James Morse , Robert Richter CC: Serge Semin , Serge Semin , Alexey Malahov , Michail Ivanov , Pavel Parkhomenko , Punnaiah Choudary Kalluri , Manish Narani , Dinh Nguyen , Rob Herring , Krzysztof Kozlowski , , , , Subject: [PATCH v2 14/15] EDAC/synopsys: Drop vendor-specific arch dependency Date: Sat, 10 Sep 2022 22:56:58 +0300 Message-ID: <20220910195659.11843-15-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> References: <20220910195659.11843-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org DW uMCTL2 DDRC EDAC driver is no longer specific to particular DDRC versions. It's generic in the most of the aspects now. So set its kernel config independently from the ZynqMP/IntelFPAG/MXC platforms. Signed-off-by: Serge Semin --- drivers/edac/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 98bcdadf4143..6aa59a0bacf1 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -486,7 +486,6 @@ config EDAC_ARMADA_XP config EDAC_SYNOPSYS tristate "Synopsys DDR Memory Controller" - depends on ARCH_ZYNQMP || ARCH_INTEL_SOCFPGA || ARCH_MXC help Support for error detection and correction on the Synopsys DDR memory controller.