From patchwork Wed Sep 20 19:10:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 13393251 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5B2FCC04FED for ; Wed, 20 Sep 2023 19:11:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=+pyc53WhT9JmHWabuQzC8XUsZCM5PDaSMIoBm0YPZAg=; b=H4yrrcFls7h+2e kqzj+EGXwwl5HLk6JYc2jlZl2DC821IDGhxr4ctT3HVJprYWb2jzAjD8X5C4yOZMrWxyLF+lmO6w8 o/Az/YleG+b3+Hx51ZQ2a6RAGFKPedB83f7nSxBQHY+e2LP4t891gdVQ3xQKtOeR+lfjgfTSanRRA J953cwVUsaMaPyS0S8XjS9Yf3pKOc+DwKUZ5k/PPQii31dRBWZn+6h29bhz2hoheQY2xS4F9MuoPO afN7bF1p6syJeZQ4tIsvcg2zsoqtezspUTy910Q6ADQvlSEy1B8mMLtqBCtydZYmJwBYLk+LMUuvT /XrCc9jDrSr+FGvlWcPQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1qj2bh-003wsU-1R; Wed, 20 Sep 2023 19:11:29 +0000 Received: from mail-lf1-x131.google.com ([2a00:1450:4864:20::131]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1qj2ba-003wpf-0l for linux-arm-kernel@lists.infradead.org; Wed, 20 Sep 2023 19:11:26 +0000 Received: by mail-lf1-x131.google.com with SMTP id 2adb3069b0e04-50306b2920dso132133e87.0 for ; Wed, 20 Sep 2023 12:11:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1695237079; x=1695841879; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=wR1JE8m9yIb2GrY6VQKOZhC73Jk1qxOxRizbrOmDB5o=; b=b8YwLIr/djAEp8ovTn9bSiBPQ+6LojC58NfzPnSnO/lAZG4eeLcjTQEjoCiiMSenJl oGvDmMhsSXRicUi0HdURLmkQI3TJM2Rmn9bH+/qeA5eH57rOKqRBsgXbDJzWS+JcM6G0 Smj90V9uf0ua1SNSKzxGJy8paNnyltEc8boHrVsr+HkkjzTa/7yuSUHY66b8JUZuHmcr lKuTwL+o/7GtOGddWWmfGUWQ6FXPrTwoXtTNwqo1IcYXZFaAWNFAkuaUnaOgkjUNRrr/ erxa3AHRDZH8SGWMHm7tEHqKq3QZe2xnEPQ4YC7FwdmklFGuUfqjAzG17PgwHzMzw/lV ik1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695237079; x=1695841879; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wR1JE8m9yIb2GrY6VQKOZhC73Jk1qxOxRizbrOmDB5o=; b=awLbphe6uz8bdqflNmdo9HNrwwjxkoT317vppnQUq8r3D5bGJarIN4Vn1XtX5iyaoa SbjXFPp/QJhsTP9JKli06PIrKZ/3tsmegO0uyGmbSVBJnrwNH6LanJxzVejF9VX7Ibfy W6zHde/oWihuEBTIN92LASaB1pFEDvIQcTM/qlVGp0nJmvZMYZLDiLz5IPtLQV4cRER+ SaYCFBAA5A33uaDmQ/Uinb724qqCCK6cbWf2of8TzfKtWiKfS5+RsomF5fc2eGxrO7dC DgzCvqGNH5Qe6Dp9tcY1xnTiLUlty43XuDdGXe5vOlLZ+zg2AGW1wsJZDKWqAtLDZt71 Rf3w== X-Gm-Message-State: AOJu0YydCTpPmoT5LdBvbioY07nTcPfQQNPCu5pCkBsaYLyfdgHSrs+F kSV61eTZwOQ31k6HqksJaCg= X-Google-Smtp-Source: AGHT+IG6GeZvz2KK7DDBg0fy99LGIWGIHeZjOEx66NYKlsdP58EJ7i/40rhVTU3icepvkciFRDsIaQ== X-Received: by 2002:a05:6512:12ca:b0:503:16ec:7153 with SMTP id p10-20020a05651212ca00b0050316ec7153mr2473011lfg.31.1695237079028; Wed, 20 Sep 2023 12:11:19 -0700 (PDT) Received: from localhost ([85.140.0.168]) by smtp.gmail.com with ESMTPSA id j28-20020ac253bc000000b0050424698d62sm57962lfh.249.2023.09.20.12.11.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 Sep 2023 12:11:18 -0700 (PDT) From: Serge Semin To: Michal Simek , Alexander Stein , Borislav Petkov , Tony Luck , James Morse , Mauro Carvalho Chehab , Robert Richter , Dinh Nguyen Cc: Serge Semin , Punnaiah Choudary Kalluri , Arnd Bergmann , Greg Kroah-Hartman , linux-arm-kernel@lists.infradead.org, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, Sherry Sun , Borislav Petkov Subject: [PATCH v4 01/20] EDAC/synopsys: Fix ECC status data and IRQ disable race condition Date: Wed, 20 Sep 2023 22:10:25 +0300 Message-ID: <20230920191059.28395-2-fancer.lancer@gmail.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20230920191059.28395-1-fancer.lancer@gmail.com> References: <20230920191059.28395-1-fancer.lancer@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230920_121122_274225_A7BA03F9 X-CRM114-Status: GOOD ( 23.65 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The race condition around the ECCCLR register access happens in the IRQ disable method called in the device remove() procedure and in the ECC IRQ handler: 1. Enable IRQ: a. ECCCLR = EN_CE | EN_UE 2. Disable IRQ: a. ECCCLR = 0 3. IRQ handler: a. ECCCLR = CLR_CE | CLR_CE_CNT | CLR_CE | CLR_CE_CNT b. ECCCLR = 0 c. ECCCLR = EN_CE | EN_UE So if the IRQ disabling procedure is called concurrently with the IRQ handler method the IRQ might be actually left enabled due to the statement 3c. The root cause of the problem is that ECCCLR register (which since v3.10a has been called as ECCCTL) has intermixed ECC status data clear flags and the IRQ enable/disable flags. Thus the IRQ disabling (clear EN flags) and handling (write 1 to clear ECC status data) procedures must be serialised around the ECCCTL register modification to prevent the race. So fix the problem described above by adding the spin-lock around the ECCCLR modifications and preventing the IRQ-handler from modifying the IRQs enable flags (there is no point in disabling the IRQ and then re-enabling it again within a single IRQ handler call, see the statements 3a/3b and 3c above). Fixes: f7824ded4149 ("EDAC/synopsys: Add support for version 3 of the Synopsys EDAC DDR") Signed-off-by: Serge Semin --- Cc: Sherry Sun Changelog v4: - This is a new patch detached from [PATCH v3 01/17] EDAC/synopsys: Fix native uMCTL2 IRQs handling procedure - Rename lock to reglock (Borislav) --- drivers/edac/synopsys_edac.c | 50 ++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index f7d37c282819..014a2176c2c1 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -300,6 +301,7 @@ struct synps_ecc_status { /** * struct synps_edac_priv - DDR memory controller private instance data. * @baseaddr: Base address of the DDR controller. + * @reglock: Concurrent CSRs access lock. * @message: Buffer for framing the event specific info. * @stat: ECC status information. * @p_data: Platform data. @@ -314,6 +316,7 @@ struct synps_ecc_status { */ struct synps_edac_priv { void __iomem *baseaddr; + spinlock_t reglock; char message[SYNPS_EDAC_MSG_SIZE]; struct synps_ecc_status stat; const struct synps_platform_data *p_data; @@ -409,7 +412,8 @@ static int zynq_get_error_info(struct synps_edac_priv *priv) static int zynqmp_get_error_info(struct synps_edac_priv *priv) { struct synps_ecc_status *p; - u32 regval, clearval = 0; + u32 regval, clearval; + unsigned long flags; void __iomem *base; base = priv->baseaddr; @@ -453,10 +457,14 @@ static int zynqmp_get_error_info(struct synps_edac_priv *priv) p->ueinfo.blknr = (regval & ECC_CEADDR1_BLKNR_MASK); p->ueinfo.data = readl(base + ECC_UESYND0_OFST); out: - clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT; - clearval |= ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT; + spin_lock_irqsave(&priv->reglock, 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); - writel(0x0, base + ECC_CLR_OFST); + + spin_unlock_irqrestore(&priv->reglock, flags); return 0; } @@ -516,24 +524,41 @@ static void handle_error(struct mem_ctl_info *mci, struct synps_ecc_status *p) static void enable_intr(struct synps_edac_priv *priv) { + unsigned long flags; + /* Enable UE/CE Interrupts */ - if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR) - writel(DDR_UE_MASK | DDR_CE_MASK, - priv->baseaddr + ECC_CLR_OFST); - else + if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) { writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK, priv->baseaddr + DDR_QOS_IRQ_EN_OFST); + return; + } + + spin_lock_irqsave(&priv->reglock, flags); + + writel(DDR_UE_MASK | DDR_CE_MASK, + priv->baseaddr + ECC_CLR_OFST); + + spin_unlock_irqrestore(&priv->reglock, flags); } static void disable_intr(struct synps_edac_priv *priv) { + unsigned long flags; + /* Disable UE/CE Interrupts */ - if (priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR) - writel(0x0, priv->baseaddr + ECC_CLR_OFST); - else + if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) { writel(DDR_QOSUE_MASK | DDR_QOSCE_MASK, priv->baseaddr + DDR_QOS_IRQ_DB_OFST); + + return; + } + + spin_lock_irqsave(&priv->reglock, flags); + + writel(0, priv->baseaddr + ECC_CLR_OFST); + + spin_unlock_irqrestore(&priv->reglock, flags); } /** @@ -577,8 +602,6 @@ static irqreturn_t intr_handler(int irq, void *dev_id) /* v3.0 of the controller does not have this register */ if (!(priv->p_data->quirks & DDR_ECC_INTR_SELF_CLEAR)) writel(regval, priv->baseaddr + DDR_QOS_IRQ_STAT_OFST); - else - enable_intr(priv); return IRQ_HANDLED; } @@ -1360,6 +1383,7 @@ static int mc_probe(struct platform_device *pdev) priv = mci->pvt_info; priv->baseaddr = baseaddr; priv->p_data = p_data; + spin_lock_init(&priv->reglock); mc_init(mci, pdev);