Received: by 2002:a05:6358:5282:b0:b5:90e7:25cb with SMTP id g2csp2719632rwa; Mon, 22 Aug 2022 12:24:24 -0700 (PDT) X-Google-Smtp-Source: AA6agR7sGrdcxKqn6jWcd0azl8OwZDr4KYHIk7+y/58LNVOOyag1eTIe/+gKv9K8o0M8mWia+ceE X-Received: by 2002:a65:5889:0:b0:428:90f3:6257 with SMTP id d9-20020a655889000000b0042890f36257mr18564720pgu.590.1661196264297; Mon, 22 Aug 2022 12:24:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661196264; cv=none; d=google.com; s=arc-20160816; b=RDOane5OEH1/J18NoQKsF/b4hLQ5r1iuv5TIzq5PmGjYCeNN+YBy6OSADjPxktaWZe 5kk6KtVGhD8wLHM2eIRut0aIPK4o1Cuv86fWRE4LcDX1sEq5WZuygbFYaz8WUPrrExqC c1tGHnshJorX5xYPagCY/JdgEyJbYHgZ2vGmj+W8P1S7IdsLh/gT46ibuTjeiAyQDyr2 gwPZWnEKxmBD6rjXopHNsas7DWdoudZRK0jMUqBkpuMTofBm/MrC+0klz4Fkks8o6wHf eXmUPg8T5JTHYxsIF0ND2BnEUaZDJPvhJ5HurTs0roFlGgDvXjcI1b4dT1r/waPvZZs0 q/6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:dkim-filter; bh=6swM1whTtvPfTaOrJikk+hfpL/sTWjJYu/9G57jnEaU=; b=mzA2ywhRdQ1EhToWqlncguOUOqRJXF8/eayG5U12gCclhBiVlPeP39JAZnxCiSRUuW ZZ7B5qeH4R+BtyTKcPPqqGF0Ueq5zFoeoTVMcOBQ1AWGG7nEzLysaLHtXeLY1WcyCh4O lBP69yOoGBYolnSGfa4+y0ED8plZcaEwKaekUW6tpQbqNZUzL6UXl/8lMsLkHLG1ykxi G5JzLFgyf2tw7XiFfpcvXAEtI/iSe3hTUyw/k7Q2nkCCfH2mjz502tDy3525mF13w9/5 XJCTsE0exHN7dULc/VJ95KkUSIW58fZhVkGnW7fBlYDzTCsA/V3HE0a0g+Rs4oedD/DG 46Jw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@baikalelectronics.ru header.s=mail header.b="E0Z4/y2T"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=baikalelectronics.ru Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id n186-20020a6327c3000000b0041cda4dc89esi14477332pgn.739.2022.08.22.12.24.10; Mon, 22 Aug 2022 12:24:24 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@baikalelectronics.ru header.s=mail header.b="E0Z4/y2T"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=baikalelectronics.ru Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238332AbiHVTWQ (ORCPT + 99 others); Mon, 22 Aug 2022 15:22:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46334 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238710AbiHVTU6 (ORCPT ); Mon, 22 Aug 2022 15:20:58 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1392F15807; Mon, 22 Aug 2022 12:20:32 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id E3F3EDA2; Mon, 22 Aug 2022 22:23:35 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com E3F3EDA2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1661196215; bh=6swM1whTtvPfTaOrJikk+hfpL/sTWjJYu/9G57jnEaU=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=E0Z4/y2TB16bsvPvNSif5uE2i/GjZiWpqaEZ+QAe86dss87n2sYQ9z+0ldrpxSjgt FFbRT+idoxGExAMS2/ZTczPBB2PFo04ls3stzAFa58ZMRSytIVDR7XQlXTeAut7Ko2 asARih1+dYjDIcjzgi7CztslfGvoZVjBlTpVW/IU= Received: from localhost (192.168.168.10) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 22 Aug 2022 22:20:21 +0300 From: Serge Semin To: 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 09/13] EDAC/synopsys: Add DFI alert_n IRQ support Date: Mon, 22 Aug 2022 22:19:52 +0300 Message-ID: <20220822191957.28546-10-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220822191957.28546-1-Sergey.Semin@baikalelectronics.ru> References: <20220822191957.28546-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 8bit X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_PASS, T_SCC_BODY_TEXT_LINE,T_SPF_PERMERROR autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In accordance with [1] DW uMCTL2 DDR controller can generate an IRQ in case if an attached SDRAM detects a CRC/Parity error. That capability is mainly applicable for the DDR4 memory which has an additional signals PARITY/ALERT_n indicating the even SDRAM address/command parity signal and alert if the parity turns to be not even. But in accordance with [1] at least the SDRAM address/command parity is calculated irrespective of the memory protocol and then sent out by means of the dfi_parity_n signal further to the DDR PHY. So depending on the DDR protocol and the DDR PHY implementation the CRC/Parity error can be checked at some point independently from the DDR devices type and then signaled via the dfi_alert_n line. In anycase it would be very much useful to catch the event and at least warn the user about problems with the DFI/SDRAM signals integrity. So here we suggest to add the DFI CRC/Parity IRQs handling support. First the IRQ line is requested by the name "dfi_e" (defined in the DT-bindings) and register its handler in case of the platform with the individual DW uMCTL2 DDRC IRQs. If individual IRQs are unavailable the common IRQ handler will call the DFI CRC/Parity event handler. Note the handler doesn't do much. It just checks the IRQ status, reads the number of errors, reports the fatal error to the MCI core and clears the IRQ status. Alas neither the erroneous SDRAM address nor the executed command are available in this case. Secondly the DFI CRC/Parity IRQ is enabled/disabled together with the ECC CE/UE interrupts in the controller probe procedure. Finally the CRC/Parity capability is advertised by the EDAC controller capabilities flags. [1] DesignWare® Cores Enhanced Universal DDR Memory Controller (uMCTL2) Databook, Version 3.91a, October 2020, p.131-132 Signed-off-by: Serge Semin --- drivers/edac/synopsys_edac.c | 78 ++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index e7d59238c5ca..cdfa0e16bc5c 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -80,6 +80,12 @@ #define ECC_POISON0_OFST 0xB8 #define ECC_POISON1_OFST 0xBC +/* DDR CRC/Parity register */ +#define DDR_CRCPARCTL0_OFST 0xC0 +#define DDR_CRCPARCTL1_OFST 0xC4 +#define DDR_CRCPARCTL2_OFST 0xC8 +#define DDR_CRCPARSTAT_OFST 0xCC + /* DDR Address map0 Registers */ #define DDR_ADDRMAP0_OFST 0x200 @@ -153,6 +159,13 @@ #define ECC_CEADDR1_BANK_MASK GENMASK(23, 16) #define ECC_CEADDR1_COL_MASK GENMASK(11, 0) +/* DDR CRC/Parity register definitions */ +#define DDR_CRCPARCTL0_CLR_ALRT_ERRCNT BIT(2) +#define DDR_CRCPARCTL0_CLR_ALRT_ERR BIT(1) +#define DDR_CRCPARCTL0_EN_ALRT_IRQ BIT(0) +#define DDR_CRCPARSTAT_ALRT_ERR BIT(16) +#define DDR_CRCPARSTAT_ALRT_CNT_MASK GENMASK(15, 0) + /* ECC Poison register shifts */ #define ECC_POISON0_RANK_MASK GENMASK(27, 24) #define ECC_POISON0_COL_MASK GENMASK(11, 0) @@ -829,6 +842,48 @@ static irqreturn_t snps_ue_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +/** + * snps_dfi_irq_handler - DFI CRC/Parity error interrupt handler. + * @irq: IRQ number. + * @dev_id: Device ID. + * + * Return: IRQ_NONE, if interrupt not set or IRQ_HANDLED otherwise. + */ +static irqreturn_t snps_dfi_irq_handler(int irq, void *dev_id) +{ + struct mem_ctl_info *mci = dev_id; + struct snps_edac_priv *priv = mci->pvt_info; + unsigned long flags; + u32 regval; + u16 ecnt; + + /* Make sure IRQ is caused by an DFI alert error */ + regval = readl(priv->baseaddr + DDR_CRCPARSTAT_OFST); + if (!(regval & DDR_CRCPARSTAT_ALRT_ERR)) + return IRQ_NONE; + + /* Just a number of CRC/Parity errors is available */ + ecnt = FIELD_GET(DDR_CRCPARSTAT_ALRT_CNT_MASK, regval); + + /* Report the detected errors with just the custom message */ + snprintf(priv->message, SNPS_EDAC_MSG_SIZE, + "DFI CRC/Parity error detected on dfi_alert_n"); + + edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, ecnt, + 0, 0, 0, 0, 0, -1, priv->message, ""); + + /* Make sure the DFI alert IRQ status is cleared */ + spin_lock_irqsave(&priv->lock, flags); + + regval = readl(priv->baseaddr + DDR_CRCPARCTL0_OFST) | + DDR_CRCPARCTL0_CLR_ALRT_ERR | DDR_CRCPARCTL0_CLR_ALRT_ERRCNT; + writel(regval, priv->baseaddr + DDR_CRCPARCTL0_OFST); + + spin_unlock_irqrestore(&priv->lock, flags); + + return IRQ_HANDLED; +} + /** * snps_com_irq_handler - Interrupt IRQ signal handler. * @irq: IRQ number. @@ -844,6 +899,8 @@ static irqreturn_t snps_com_irq_handler(int irq, void *dev_id) rc |= snps_ue_irq_handler(irq, dev_id); + rc |= snps_dfi_irq_handler(irq, dev_id); + return rc; } @@ -859,11 +916,16 @@ static void snps_enable_irq(struct snps_edac_priv *priv) return; } - /* IRQs Enable/Disable feature has been available since v3.10a */ + /* + * ECC IRQs Enable/Disable feature has been available since v3.10a, + * while CRC/Parity interrupts control - since v2.10a. + */ spin_lock_irqsave(&priv->lock, flags); writel(ECC_CTRL_EN_CE_IRQ | ECC_CTRL_EN_UE_IRQ, priv->baseaddr + ECC_CLR_OFST); + writel(DDR_CRCPARCTL0_EN_ALRT_IRQ, + priv->baseaddr + DDR_CRCPARCTL0_OFST); spin_unlock_irqrestore(&priv->lock, flags); } @@ -883,6 +945,7 @@ static void snps_disable_irq(struct snps_edac_priv *priv) spin_lock_irqsave(&priv->lock, flags); writel(0, priv->baseaddr + ECC_CLR_OFST); + writel(0, priv->baseaddr + DDR_CRCPARCTL0_OFST); spin_unlock_irqrestore(&priv->lock, flags); } @@ -1483,7 +1546,8 @@ static struct mem_ctl_info *snps_mc_create(struct snps_edac_priv *priv) mci->mtype_cap = MEM_FLAG_LPDDR | MEM_FLAG_DDR2 | MEM_FLAG_LPDDR2 | MEM_FLAG_DDR3 | MEM_FLAG_LPDDR3 | MEM_FLAG_DDR4 | MEM_FLAG_LPDDR4; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; + mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_PARITY; + mci->edac_cap = mci->edac_ctl_cap; if (priv->info.caps & SNPS_CAP_ECC_SCRUB) { mci->scrub_mode = SCRUB_HW_SRC; @@ -1493,7 +1557,6 @@ static struct mem_ctl_info *snps_mc_create(struct snps_edac_priv *priv) mci->scrub_cap = SCRUB_FLAG_SW_SRC; } - mci->edac_cap = EDAC_FLAG_SECDED; mci->ctl_name = "snps_umctl2_ddrc"; mci->dev_name = SNPS_EDAC_MOD_STRING; mci->mod_name = SNPS_EDAC_MOD_VER; @@ -1559,6 +1622,15 @@ static int snps_request_ind_irq(struct mem_ctl_info *mci) return rc; } + irq = platform_get_irq_byname_optional(priv->pdev, "dfi_e"); + if (irq > 0) { + rc = devm_request_irq(dev, irq, snps_dfi_irq_handler, 0, "dfi_e", mci); + if (rc) { + edac_printk(KERN_ERR, EDAC_MC, "Failed to request DFI IRQ\n"); + return rc; + } + } + return 0; } -- 2.35.1