From patchwork Mon Aug 24 02:42:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290639 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4826-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwF65fT2z1yCF for ; Mon, 24 Aug 2026 12:42:50 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwF61DQHz2y2P; Mon, 24 Aug 2026 12:42:50 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539370; cv=none; b=RpufzvDlGOEcmZDPRgVE/5C3aa/s2bpGLG0cM8ecknKuxrwv3nFjwC0n6136xQsoB/ahsYzisEfurWR1ROC/4XPApH4pVdmrRg+JOg3UFWKfTllo1DS8LCNNqP0AFfekCvperiMT44+kS3JsOuRc2pKiQYqaJqhaN7CgEinQmLB5mQ/wlgVp+2ZlPlQJXIMBPuGxk/KRx7OLSbcOO0DSL2rZJUR3v/aaWzIl5jLxNILB55rR0tw5X2vmzRZqYxEin+YqVBtN/eqnNdGNY0DaHwZlaDNNyj3IMc8h8I3ye5mCU07IRcnya43qGh/UGKz1/GlUM/xqxDkP2gjN61CL0A== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539370; c=relaxed/relaxed; bh=jNQAJY0VrRNOcqodeuBlYf2NAb7EX7MKHfLgKkoDvxE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=hvprqPdE15uwfAi5bZTwAkqUUQXnMfTGK4KV3+ulxN40xBG/AJf5aRFA22+H87DO/ZukkD9mDpxNBrVLyUFvJVnxKlidz87Ndq0an7cD50AxlqoANT3govCravs3C9eICvZjEhxkBDKfKTbXpQciiC8oaNl+lB4I5xWSpBeP/czQYzz985b1EJxVq317UuEZTLCAndOW8ZQfVPe66uYaOoqL0ClKBnYxvC/obcy8Cb03CbNsMGV+nqWQu3wNJkJ+2Upf9vbKKGwEIINQ5P5tb04wpNtHjxxemaznxRSyt1Sx/0h9j23+A8bjH/Ory5DknTFTCY2RpOJh32XJgw8zrw== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwF52rnFz2xmk for ; Mon, 24 Aug 2026 12:42:49 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:29 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:29 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:28 +0800 Subject: [PATCH v2 1/8] dt-bindings: edac: aspeed: Add AST2700 SDRAM EDAC X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-1-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen , "Krzysztof Kozlowski" X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=1457; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=/rj5B9ojWffAdYkp2s4TIp84wfNqe/zSqKMEbEuHOX4=; b=TaibQvv4TpzRvvyoXVzgOjoAI303zuv8TcSaD2VQghxWh6N8J2Ejb/YKubUDy2LwQlCUnU9Tz kHqYF4tiE2rAeuS52ZOANT7tGZfw1zUsDxd0E3XsChaWawY4LDnRyqW X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org Add the "aspeed,ast2700-sdram-edac" compatible and note DDR5 support. Signed-off-by: Ryan Chen Acked-by: Krzysztof Kozlowski --- .../devicetree/bindings/edac/aspeed,ast2400-sdram-edac.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/edac/aspeed,ast2400-sdram-edac.yaml b/Documentation/devicetree/bindings/edac/aspeed,ast2400-sdram-edac.yaml index 09735826d707..685b6815f293 100644 --- a/Documentation/devicetree/bindings/edac/aspeed,ast2400-sdram-edac.yaml +++ b/Documentation/devicetree/bindings/edac/aspeed,ast2400-sdram-edac.yaml @@ -10,8 +10,9 @@ maintainers: - Stefan Schaeckeler description: > - The Aspeed BMC SoC supports DDR3 and DDR4 memory with and without ECC (error - correction check). + The Aspeed BMC SoCs support DDR memory with and without ECC (error + correction check): DDR3 and DDR4 on the AST2400, AST2500 and AST2600, + and DDR4 and DDR5 on the AST2700. The memory controller supports SECDED (single bit error correction, double bit error detection) and single bit error auto scrubbing by reserving 8 bits for @@ -25,6 +26,7 @@ properties: - aspeed,ast2400-sdram-edac - aspeed,ast2500-sdram-edac - aspeed,ast2600-sdram-edac + - aspeed,ast2700-sdram-edac reg: maxItems: 1 From patchwork Mon Aug 24 02:42:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290643 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:21b9:f100::1; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4827-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:21b9:f100::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFG24w4z1yCF for ; Mon, 24 Aug 2026 12:42:58 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwF70r4Kz2y2c; Mon, 24 Aug 2026 12:42:51 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539371; cv=none; b=Qze3DWxhMHQb2KEOowNb3X9rW4GG3aJPCa4namJYMRwkNxextVYGELFjfEOqCotLXoCpn32ZEx+QE3M7GsmjZttHH/uwl+OjA3VjwpDy+gqBG+goKDZ2cWFqn2nY9TbiQGDCq3bv7m3RF0X2S087cnSmLH2N//nPPLu/3hHi8/oAIfkvRD1t7lPJyjbF6kexqX0ythfRHVkX8BlIDDsJuVdJkSPrk3Yauz0DFFXjRulpMC4uGZCaNrnphxjRvWyj1Rvm/Pjmks6EgrtaZmnFZn3JiorX9pQquCaxmt3riwTsbBvuLUTHYXju7JFZxfFX0dHP1I+DrbGwN7mrb1V06A== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539371; c=relaxed/relaxed; bh=N6OJ989F/+0jEE5cnJJECukQ9CjEfoUAMRDFiLpoOLo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=BfEGfcIXyre9RjZ3sFSxr5dhA+/yaskdhaJHw11HaEv5RVp0Xu+HyOjqtBopjjCtDU3R0JyQI3ZyZDIsj/Qnoq5dNMOVQKYxIeeiMAtyB0+nlGkZnCDmQG+HTv2prsEzVfRzwAG1NC6AhtQTaCdHg5CPsmxxDuinFV/rmX+ybnsUuY/J6JPZ+4FX3Q4byDzhLmU2ooAatL8adk7Cb4UD2E3Z8sRyNO/fer/ez9+rouoi+bDtZ7Q2/EcH+EOguQaGd9FYG0ieiSJiYJeM1uimm0LUqskFmJ9nNqj1Hw056wIIBFMI03pxA97xZ13VTpGY+Hs5XOWO3TBe8o1MFqQpgQ== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwF62vxHz2xmk for ; Mon, 24 Aug 2026 12:42:50 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:29 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:29 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:29 +0800 Subject: [PATCH v2 2/8] EDAC/aspeed: Set the DIMM grain X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-2-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen , X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=1310; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=HAKuO93Qq40zQKSxoIqd6AgYapN0t/tUgR+0VfcG6gw=; b=pWMGHcJsIcNVW6fGk94Ijg8TINjEYsz1FD6Ls8QarH71DmsGHNYs0v+MeawD+m42IUSfAQtqJ Rx6vngxHGfQDWICRK+3nRef9Xsm4UkjhAOQp7WRYgmaaN6DkI5RH2vE X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org The driver never sets dimm->grain, leaving it zero. Since commit 3724ace582d9 ("EDAC/mc: Fix grain_bits calculation") edac_raw_mc_handle_error() runs WARN_ON_ONCE(!e->grain) and forces the grain to 1, so the first ECC error reported on any Aspeed BMC SoC emits a warning splat, e.g. on the AST2600: WARNING: CPU: 0 PID: 0 at drivers/edac/edac_mc.c:924 edac_raw_mc_handle_error+0x4b4/0x604 ... edac_raw_mc_handle_error from edac_mc_handle_error+0x364/0x4a8 edac_mc_handle_error from count_rec+0xdc/0x124 count_rec from mcr_isr+0x110/0x1e8 Fixes: 9b7e6242ee4e ("EDAC, aspeed: Add an Aspeed AST2500 EDAC driver") Signed-off-by: Ryan Chen Cc: stable@vger.kernel.org --- drivers/edac/aspeed_edac.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 6e069b255595..83d60414f89a 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -266,6 +266,7 @@ static int init_csrows(struct mem_ctl_info *mci) dimm->mtype = dram_type; dimm->edac_mode = EDAC_SECDED; dimm->nr_pages = nr_pages / csrow->nr_channels; + dimm->grain = 16; dev_dbg(mci->pdev, "initialized dimm with first_page=0x%lx and nr_pages=0x%x\n", csrow->first_page, nr_pages); From patchwork Mon Aug 24 02:42:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290640 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:21b9:f100::1; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4828-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:21b9:f100::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (secp384r1 raw public key) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFD19BWz1xwG for ; Mon, 24 Aug 2026 12:42:56 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwF80kq5z2y2g; Mon, 24 Aug 2026 12:42:52 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539372; cv=none; b=nox2iTDIaH41p19JgWIqaeH/BV3X51rTcI2k99GnX4k4VhEkQBg4beyjwBczi6YOazk2jKTh36y3PCk4vBWLjz03cs1FHWU/T5CgCnIzyuopxcZugZcjIogf53XVYRqzSHmf8zo6Z1Lbvxd81bN1fZCfke6CRxTif1FcaK98l5lnAjwkeFFYkXQWzOkDkeWHIKVzg4ouCAfAzirXxpJDvJYuAEuHisqMiitoGHR0Z5CgtirjiwOJBw8cLnZjOxWQMFGcppNx0oJe1c7vXKQvcWmVL2vcNMWEdyWE/ivxCNHAMhD53Xt05vPo4jR613YrxFtRphA6Alo8nQ4SME+klA== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539372; c=relaxed/relaxed; bh=StOLANgoUDdDCghzEyyTo31Qu80FIuZFNWrDA8Xal/Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=RHGdE5OzhfKRSZKNOp/gNQAlaZ22O6EBIFIYMZb0Qj8WTTilUn9R9FbjSzDSbCunaE68M4AShkNj5euT2DwZwQExItsEQ3pPwuIpN9LoaCZ5AhTCwyVNsyhfyuaYlBFDrCfJrMDtErCZPMYc6Cp7RRf6c4kta62H/wPCg+g/Gf4xD73cDmIKoNLxalYauOuc6BQjfeSfotOSCZpRmQHENP1YLNK7wVN5J1fUonPn214tu3d1uf/fLMQDObLlsJFCACeHsQ0HZtZsOdUo6WiuQJX1MBE3EM5op6k37Uf1DbF/Gjm8IKd5gMTzyOwAl3s0DReLw8LhLitbecz7fiaRZg== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwF72Rl0z2xmk for ; Mon, 24 Aug 2026 12:42:51 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:29 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:29 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:30 +0800 Subject: [PATCH v2 3/8] EDAC/aspeed: Free the interrupt before the mem_ctl_info on remove X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-3-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen , X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=1363; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=RlxiTc6ufbAPp2W9fkd50aRtYznC++m4JM40pI/YrqE=; b=gpm27cUcRMtuWzCYAMZDJ+ZRjHayMCjYlYb1GvBw7j/JjEkz5DoJugDkwdsgHS1YKJBXoglg0 LrgCW0p3PfhD0Ihn/PVxqB2zZL+Dut7Vd3Y6FJ9p6NtwOpzsuoeFiW4 X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org The ECC interrupt is devm-managed, so it is only released after .remove() has returned, and masking the controller does not wait for a handler already running on another CPU. edac_mc_free() can therefore free the mem_ctl_info the handler uses as its context while it is still running. Fix the ordering and synchronise by freeing the interrupt prior to releasing related memory. Fixes: 9b7e6242ee4e ("EDAC, aspeed: Add an Aspeed AST2500 EDAC driver") Signed-off-by: Ryan Chen Cc: stable@vger.kernel.org --- Changes in v2: - New patch. --- drivers/edac/aspeed_edac.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 83d60414f89a..e05ebed5c2f2 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -359,11 +359,16 @@ static int aspeed_probe(struct platform_device *pdev) static void aspeed_remove(struct platform_device *pdev) { struct mem_ctl_info *mci; + int irq; /* disable interrupts */ regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL, ASPEED_MCR_INTR_CTRL_ENABLE, 0); + irq = platform_get_irq(pdev, 0); + WARN_ON(irq < 0); + devm_free_irq(&pdev->dev, irq, platform_get_drvdata(pdev)); + /* free resources */ mci = edac_mc_del_mc(&pdev->dev); if (mci) From patchwork Mon Aug 24 02:42:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290641 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:21b9:f100::1; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4829-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:21b9:f100::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFD53GWz1yCF for ; Mon, 24 Aug 2026 12:42:56 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwF912jBz2y2h; Mon, 24 Aug 2026 12:42:53 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539373; cv=none; b=WXtYN5Q0wh1vucCf2ycnp3a6lBJtRiiI8OyjxU473IsT0ng9GLCVS9fNgglGdlE4MN7fDKkwbLpIYLt+SQlcryKZBnXkG/nrQ9qc6u1ORKCfWbQDNTKbCfosIaB9KCtd6NuzCntHPt9rprmUYjlsgQGeFrntPIerzWn6miPDiNFgjs3pNB1aHLQa///6+vKCf3s907frSaOnDFuHxYw+w1Ixfr+6Fw4ZlzUD0jf9u7lC71uRKGTZmpUgVjcoAC7cHZraxuWhZ9KB4Dd42zyAOk5PEqYb1hqHbWeOhDTI7bzO5YIoAo4hR8fqUN1RTTOUprxn3l8jdJ7JzhsCU+zK5A== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539373; c=relaxed/relaxed; bh=Bv42BCq0VbJx83T3QQNyUqvHP1MGmtolrNTMYYRob5Y=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=EhrV0qrpdVt0dRFEA5O+vc5BZDAeKc1nBgYqlaQasMgsswNME5rbnDlds6v3iTvCC5c2y8u+K6NC70xsdohhv0INehusxhIdOcxEECkF1Gi7si4Fj8trUCOdiYzIi5mc8fx2XkaN0Ur3UpsSB5AsWkVrrr7p0oPZknNsZCO4LelhrJeZ+p53BZBqCj24qYJhNtrkyErs7XHo/A/xvzzjIlf9YCWqfAWEMIBtHIIneCcvwOYviIRjvnILC2dS/X4oQ7VTQAyXzuH9RNtLQQRJ4KbDDYa3H3YJH6GTtoOIGxdpzyJilLJSNhjMN1g2rioQJbe6wNMySMAxJ1/aeT6Qiw== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwF82Jbsz2xmk for ; Mon, 24 Aug 2026 12:42:52 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:29 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:29 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:31 +0800 Subject: [PATCH v2 4/8] EDAC/aspeed: Clean up whitespace and include ordering X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-4-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=4626; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=FhGqCgC1qcv7kHcNVhXGaiiu15ASlL/TX82CfVZ7NtU=; b=GoygC2E3grvnPd/Rs5Ery9rOw8CZ2YdTHWs1JTllbAufHdcDhqmniCvIr3gty9x43Vlyq1Pzb X3NhroraJhdCdJOYlFiEs3dh3IsGOe5FHGgeBVNvzZoIfwSoJOtCGuK X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org The driver separates functions and definition groups with two blank lines where the kernel style uses one, its headers are not sorted, and it includes linux/stop_machine.h without using it. Collapse the double blank lines, drop the unused include and sort the rest alphabetically so the following changes start from a consistent style. Signed-off-by: Ryan Chen --- drivers/edac/aspeed_edac.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index e05ebed5c2f2..cd2a6fcca355 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -4,20 +4,17 @@ */ #include -#include #include #include -#include -#include #include +#include #include +#include #include #include "edac_module.h" - #define DRV_NAME "aspeed-edac" - #define ASPEED_MCR_PROT 0x00 /* protection key register */ #define ASPEED_MCR_CONF 0x04 /* configuration register */ #define ASPEED_MCR_INTR_CTRL 0x50 /* interrupt control/status register */ @@ -25,19 +22,16 @@ #define ASPEED_MCR_ADDR_REC 0x5c /* address of last recoverable error */ #define ASPEED_MCR_LAST ASPEED_MCR_ADDR_REC - -#define ASPEED_MCR_PROT_PASSWD 0xfc600309 -#define ASPEED_MCR_CONF_DRAM_TYPE BIT(4) -#define ASPEED_MCR_CONF_ECC BIT(7) -#define ASPEED_MCR_INTR_CTRL_CLEAR BIT(31) -#define ASPEED_MCR_INTR_CTRL_CNT_REC GENMASK(23, 16) -#define ASPEED_MCR_INTR_CTRL_CNT_UNREC GENMASK(15, 12) -#define ASPEED_MCR_INTR_CTRL_ENABLE (BIT(0) | BIT(1)) - +#define ASPEED_MCR_PROT_PASSWD 0xfc600309 +#define ASPEED_MCR_CONF_DRAM_TYPE BIT(4) +#define ASPEED_MCR_CONF_ECC BIT(7) +#define ASPEED_MCR_INTR_CTRL_CLEAR BIT(31) +#define ASPEED_MCR_INTR_CTRL_CNT_REC GENMASK(23, 16) +#define ASPEED_MCR_INTR_CTRL_CNT_UNREC GENMASK(15, 12) +#define ASPEED_MCR_INTR_CTRL_ENABLE (BIT(0) | BIT(1)) static struct regmap *aspeed_regmap; - static int regmap_reg_write(void *context, unsigned int reg, unsigned int val) { void __iomem *regs = (void __iomem *)context; @@ -53,7 +47,6 @@ static int regmap_reg_write(void *context, unsigned int reg, unsigned int val) return 0; } - static int regmap_reg_read(void *context, unsigned int reg, unsigned int *val) { void __iomem *regs = (void __iomem *)context; @@ -76,7 +69,6 @@ static bool regmap_is_volatile(struct device *dev, unsigned int reg) } } - static const struct regmap_config aspeed_regmap_config = { .reg_bits = 32, .val_bits = 32, @@ -88,7 +80,6 @@ static const struct regmap_config aspeed_regmap_config = { .fast_io = true, }; - static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) { struct csrow_info *csrow = mci->csrows[0]; @@ -120,7 +111,6 @@ static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) 0, 0, -1, "", ""); } - static void count_un_rec(struct mem_ctl_info *mci, u8 un_rec_cnt, u32 un_rec_addr) { @@ -153,7 +143,6 @@ static void count_un_rec(struct mem_ctl_info *mci, u8 un_rec_cnt, } } - static irqreturn_t mcr_isr(int irq, void *arg) { struct mem_ctl_info *mci = arg; @@ -200,7 +189,6 @@ static irqreturn_t mcr_isr(int irq, void *arg) return IRQ_HANDLED; } - static int config_irq(void *ctx, struct platform_device *pdev) { int irq; @@ -225,7 +213,6 @@ static int config_irq(void *ctx, struct platform_device *pdev) return 0; } - static int init_csrows(struct mem_ctl_info *mci) { struct csrow_info *csrow = mci->csrows[0]; @@ -274,7 +261,6 @@ static int init_csrows(struct mem_ctl_info *mci) return 0; } - static int aspeed_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -355,7 +341,6 @@ static int aspeed_probe(struct platform_device *pdev) return rc; } - static void aspeed_remove(struct platform_device *pdev) { struct mem_ctl_info *mci; @@ -375,7 +360,6 @@ static void aspeed_remove(struct platform_device *pdev) edac_mc_free(mci); } - static const struct of_device_id aspeed_of_match[] = { { .compatible = "aspeed,ast2400-sdram-edac" }, { .compatible = "aspeed,ast2500-sdram-edac" }, From patchwork Mon Aug 24 02:42:32 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290642 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:21b9:f100::1; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4830-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:21b9:f100::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFF5rjfz1xwG for ; Mon, 24 Aug 2026 12:42:57 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwFB0gn9z2y71; Mon, 24 Aug 2026 12:42:54 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539374; cv=none; b=PatpfSQ5HgKeWlOSivjpauUlg7XI7SLkp0b+2HKaQUNlr4kXe56q7sgNtYgawTNPXITy0CtRqZOarzkUV5+RP5yEp3b2xdPGsrjJdkdrl2sp+qTX8Rqn/MT/iSChUYEkUxoJV4MEhe7/Z7vsOyUAyee3d1kBfyTthJxtC4zBYLZ0EXGauNADkWlJF3pUu5HBZpCye4rWh0OciSfbK2vU8Y4WajffxQuxdQNjjEL5PfsVfBUcecXilFDcVGtvoGGL37up6enrWat6hY/RyrOrM4L5+gUR0/kSdGef7ktDz1OyxSwCWugM+OjbMZWO6ukfnnmlAjB+dtyDTpfRDvxe3A== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539374; c=relaxed/relaxed; bh=WzfGEJLpHwH50IZOK4KkDMKN3sG+LbnJq7S0viXLif8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=m6tLuz5ygfrH1snMDjV93GXqGT0o1Kd/+2H5zPS3nicSrspNADn4FF1piDUWdqf0WJvVQk+DHinSVB4++Z3gYMJze/8CpDGf4831Z8Be4DLzsWe3obFvPyLrEKhZYJjoUpF4qvzKhGkBOL8o80Fm8YUbOzeMQgyhMcTTgpZTBacUPr1i7J0K92ZXdwZIlK6tiEiMtkg/2MavqbXsyU0IIfC1AGAUiv3mbHvlJ/9jDWmtph8SxQLaDgM9mAt566933o8gZB93bLmUEfQ5OFDKeZ0dFSaH6fSENnke4vcQJYa33EaopE9LHozR2hk3lIqE5n454NBHofSRucY8CEtaQg== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwF92ZtTz2xmk for ; Mon, 24 Aug 2026 12:42:53 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:29 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:29 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:32 +0800 Subject: [PATCH v2 5/8] EDAC/aspeed: Free the mem_ctl_info unconditionally on remove X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-5-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=1565; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=7kVBSW+iJq7iG0C/gaN+W7UHNDDfaeN9Q8zh7Gh7SjI=; b=tmzcNbO6l4v/ZjpLF1sRvvnABHILvPaf2m5qsCrYx7e1Xvo3KWS7sazk+K6B0sEq/XNQbH7A6 4oPY8pE0WSJCTkKMfdhwd+asMen7kmrQbIYF9UuVD/Bt79CialmOoxG X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org aspeed_remove() is a driver .remove callback, so it only runs for a device that has already probed successfully and registered its mem_ctl_info. In that case edac_mc_del_mc() always returns the same, valid pointer, and the NULL check on its return value can never be false. Fetch the mem_ctl_info from the platform device's driver data instead and free it unconditionally, dropping the redundant check. This also decouples the teardown from the return value of edac_mc_del_mc(). Signed-off-by: Ryan Chen --- drivers/edac/aspeed_edac.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index cd2a6fcca355..352910e1defc 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -343,7 +343,7 @@ static int aspeed_probe(struct platform_device *pdev) static void aspeed_remove(struct platform_device *pdev) { - struct mem_ctl_info *mci; + struct mem_ctl_info *mci = platform_get_drvdata(pdev); int irq; /* disable interrupts */ @@ -352,12 +352,11 @@ static void aspeed_remove(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); WARN_ON(irq < 0); - devm_free_irq(&pdev->dev, irq, platform_get_drvdata(pdev)); + devm_free_irq(&pdev->dev, irq, mci); /* free resources */ - mci = edac_mc_del_mc(&pdev->dev); - if (mci) - edac_mc_free(mci); + edac_mc_del_mc(&pdev->dev); + edac_mc_free(mci); } static const struct of_device_id aspeed_of_match[] = { From patchwork Mon Aug 24 02:42:33 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290644 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4831-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFH0jBfz1xwG for ; Mon, 24 Aug 2026 12:42:59 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwFC2Qr3z2y83; Mon, 24 Aug 2026 12:42:55 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539375; cv=none; b=AmuK+inLADLAJ9trOvThAZzfHfFbC4U1EkBZa0/gJhx6Id1NLHEp4FClRmL1dOAhdOcESaqxqRR4XnF7Hxc4mm4oGHNY9a2E2dIPS1QAO8hjv2cKFmdk9Tf86jQoi9prVT5GB/TfWlBaTh65P7ARjLjsgG8ciIPvJPVCtH/TO3QP3vUbdQ9xZ9DRgSoA1/k6bk1pcOnyLPoZLCRGkPyo/S/aphmENE70KzLnBovWDke73AONDUL2yttAKFd5YGjfkcU7+eB19YFtkC+NuCa0q0yeDAR0zM+oXjpPveyYzaKCKwT2nZcZc5XoxP142N5Ifyy45YEizQt0xDTkYzDGBA== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539375; c=relaxed/relaxed; bh=AtdJnHwtSGOPKdAmHUln/ZIRoe7Fx0736qJeEmHyjB4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=GQtT2xLcmEaSoaDLlnN6T2OHwDkSNhW7t1Rnuc4KYg/WeKQcmPUOvactEa/RfoWcNwwJK/PU6iftfaYTxvr3+H3UAVDPB3sOH/d/ydSrKAeFq3yfrAX8s7SXq6sXgbdTnWAeF2eJ1RVx6RSG9SfBQh8QFfdvmiirgThJvdEXCXGvB3d59FTMTSb+7kEYn5594SCueuVTn4vaXP3VZHgoFMbelCztJ+xG6lOptJjGxrj33BV/ef7fbciEuen8Nxsn2o+j3diVXgKtpn9rYOq/JWxgVzx1Q2+0RVdPUdndqSoSFETiAHBswQ2qdiaFBp1akSO4lrZXKDmuAnMW2JYirg== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwFB2Dp0z2xmk for ; Mon, 24 Aug 2026 12:42:54 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:29 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:29 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:33 +0800 Subject: [PATCH v2 6/8] EDAC/aspeed: Replace regmap with direct register access X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-6-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=9641; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=psxRIoxnIOnKjSdmh+wrPYhekj1Z2QyYL+Qf6j/9Bq0=; b=FTiurfxA95Wui5itLcd9MtzO1dXWHIpGoLUst5PY0wDUGWIJV/haaBeerkcZ1x4t8B2iuwbTi Y2OyeAYmQX4CfYuDRQF4lHPfM53rFcPDMRjC7synJiDfucmaS2ac7n/ X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org The driver instantiates its own regmap purely as an MMIO wrapper: it has no register cache, uses custom .reg_read()/.reg_write() callbacks, and is not shared as a syscon with other drivers. So it brings nothing here beyond the spinlock that regmap takes around each access when fast_io is set. Drop the regmap and access the registers directly with readl()/writel() under an explicit raw spinlock, held across the whole read-modify-write so the controller is unlocked once around the grouped writes rather than on every register write. Annotate the register base with __guarded_by() so that, under CONFIG_WARN_CONTEXT_ANALYSIS, the compiler checks at build time that every hardware register access is performed while holding the lock. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ryan Chen --- Changes in v2: - Take the register lock with the irqsave variant in init_csrows() and in aspeed_probe(); the interrupt handler takes the same lock in hardirq context, so acquiring it with interrupts enabled would trip lockdep. - Move the dev_dbg() of the interrupt status register out of the raw_spinlock critical section in the interrupt handler. - Opt aspeed_edac.o into context analysis in drivers/edac/Makefile, so that the __guarded_by() annotation is actually checked. - Note in the interrupt handler that the counter and interrupt flag fields are read-only, so writing back the read value is harmless. --- drivers/edac/Makefile | 1 + drivers/edac/aspeed_edac.c | 131 +++++++++++++++++---------------------------- 2 files changed, 51 insertions(+), 81 deletions(-) diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index a37534300ab9..9215dd0bb835 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o obj-$(CONFIG_EDAC_TI) += ti_edac.o obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o +CONTEXT_ANALYSIS_aspeed_edac.o := y obj-$(CONFIG_EDAC_ASPEED) += aspeed_edac.o obj-$(CONFIG_EDAC_BLUEFIELD) += bluefield_edac.o obj-$(CONFIG_EDAC_DMC520) += dmc520_edac.o diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 352910e1defc..26d2c456cc0d 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -3,6 +3,7 @@ * Copyright 2018, 2019 Cisco Systems */ +#include #include #include #include @@ -10,7 +11,7 @@ #include #include #include -#include +#include #include "edac_module.h" #define DRV_NAME "aspeed-edac" @@ -20,7 +21,6 @@ #define ASPEED_MCR_INTR_CTRL 0x50 /* interrupt control/status register */ #define ASPEED_MCR_ADDR_UNREC 0x58 /* address of first un-recoverable error */ #define ASPEED_MCR_ADDR_REC 0x5c /* address of last recoverable error */ -#define ASPEED_MCR_LAST ASPEED_MCR_ADDR_REC #define ASPEED_MCR_PROT_PASSWD 0xfc600309 #define ASPEED_MCR_CONF_DRAM_TYPE BIT(4) @@ -30,55 +30,8 @@ #define ASPEED_MCR_INTR_CTRL_CNT_UNREC GENMASK(15, 12) #define ASPEED_MCR_INTR_CTRL_ENABLE (BIT(0) | BIT(1)) -static struct regmap *aspeed_regmap; - -static int regmap_reg_write(void *context, unsigned int reg, unsigned int val) -{ - void __iomem *regs = (void __iomem *)context; - - /* enable write to MCR register set */ - writel(ASPEED_MCR_PROT_PASSWD, regs + ASPEED_MCR_PROT); - - writel(val, regs + reg); - - /* disable write to MCR register set */ - writel(~ASPEED_MCR_PROT_PASSWD, regs + ASPEED_MCR_PROT); - - return 0; -} - -static int regmap_reg_read(void *context, unsigned int reg, unsigned int *val) -{ - void __iomem *regs = (void __iomem *)context; - - *val = readl(regs + reg); - - return 0; -} - -static bool regmap_is_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case ASPEED_MCR_PROT: - case ASPEED_MCR_INTR_CTRL: - case ASPEED_MCR_ADDR_UNREC: - case ASPEED_MCR_ADDR_REC: - return true; - default: - return false; - } -} - -static const struct regmap_config aspeed_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = ASPEED_MCR_LAST, - .reg_write = regmap_reg_write, - .reg_read = regmap_reg_read, - .volatile_reg = regmap_is_volatile, - .fast_io = true, -}; +static DEFINE_RAW_SPINLOCK(aspeed_lock); +static void __iomem *aspeed_regs __guarded_by(&aspeed_lock); static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) { @@ -147,10 +100,27 @@ static irqreturn_t mcr_isr(int irq, void *arg) { struct mem_ctl_info *mci = arg; u32 rec_addr, un_rec_addr; - u32 reg50, reg5c, reg58; - u8 rec_cnt, un_rec_cnt; + u8 rec_cnt, un_rec_cnt; + u32 reg50; + + scoped_guard(raw_spinlock, &aspeed_lock) { + reg50 = readl(aspeed_regs + ASPEED_MCR_INTR_CTRL); + un_rec_addr = readl(aspeed_regs + ASPEED_MCR_ADDR_UNREC); + rec_addr = readl(aspeed_regs + ASPEED_MCR_ADDR_REC); + + /* + * Clearing the counters needs a set-then-clear of CLEAR. The + * counter and interrupt flag fields are read-only, so writing + * back the values read above leaves them unaffected. + */ + writel(ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); + writel(reg50 | ASPEED_MCR_INTR_CTRL_CLEAR, + aspeed_regs + ASPEED_MCR_INTR_CTRL); + writel(reg50 & ~ASPEED_MCR_INTR_CTRL_CLEAR, + aspeed_regs + ASPEED_MCR_INTR_CTRL); + writel(~ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); + } - regmap_read(aspeed_regmap, ASPEED_MCR_INTR_CTRL, ®50); dev_dbg(mci->pdev, "received edac interrupt w/ mcr register 50: 0x%x\n", reg50); @@ -161,20 +131,6 @@ static irqreturn_t mcr_isr(int irq, void *arg) dev_dbg(mci->pdev, "%d recoverable interrupts and %d unrecoverable interrupts\n", rec_cnt, un_rec_cnt); - regmap_read(aspeed_regmap, ASPEED_MCR_ADDR_UNREC, ®58); - un_rec_addr = reg58; - - regmap_read(aspeed_regmap, ASPEED_MCR_ADDR_REC, ®5c); - rec_addr = reg5c; - - /* clear interrupt flags and error counters: */ - regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL, - ASPEED_MCR_INTR_CTRL_CLEAR, - ASPEED_MCR_INTR_CTRL_CLEAR); - - regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL, - ASPEED_MCR_INTR_CTRL_CLEAR, 0); - /* process recoverable and unrecoverable errors */ count_rec(mci, rec_cnt, rec_addr); count_un_rec(mci, un_rec_cnt, un_rec_addr); @@ -182,13 +138,31 @@ static irqreturn_t mcr_isr(int irq, void *arg) if (!rec_cnt && !un_rec_cnt) dev_dbg(mci->pdev, "received edac interrupt, but did not find any ECC counters\n"); - regmap_read(aspeed_regmap, ASPEED_MCR_INTR_CTRL, ®50); + scoped_guard(raw_spinlock, &aspeed_lock) + reg50 = readl(aspeed_regs + ASPEED_MCR_INTR_CTRL); dev_dbg(mci->pdev, "edac interrupt handled. mcr reg 50 is now: 0x%x\n", reg50); return IRQ_HANDLED; } +static void aspeed_set_irq(bool enable) +{ + u32 val; + + guard(raw_spinlock_irqsave)(&aspeed_lock); + + val = readl(aspeed_regs + ASPEED_MCR_INTR_CTRL); + if (enable) + val |= ASPEED_MCR_INTR_CTRL_ENABLE; + else + val &= ~ASPEED_MCR_INTR_CTRL_ENABLE; + + writel(ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); + writel(val, aspeed_regs + ASPEED_MCR_INTR_CTRL); + writel(~ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); +} + static int config_irq(void *ctx, struct platform_device *pdev) { int irq; @@ -206,9 +180,7 @@ static int config_irq(void *ctx, struct platform_device *pdev) return rc; /* enable interrupts */ - regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL, - ASPEED_MCR_INTR_CTRL_ENABLE, - ASPEED_MCR_INTR_CTRL_ENABLE); + aspeed_set_irq(true); return 0; } @@ -246,7 +218,8 @@ static int init_csrows(struct mem_ctl_info *mci) nr_pages = resource_size(&r) >> PAGE_SHIFT; csrow->last_page = csrow->first_page + nr_pages - 1; - regmap_read(aspeed_regmap, ASPEED_MCR_CONF, ®04); + scoped_guard(raw_spinlock_irqsave, &aspeed_lock) + reg04 = readl(aspeed_regs + ASPEED_MCR_CONF); dram_type = (reg04 & ASPEED_MCR_CONF_DRAM_TYPE) ? MEM_DDR4 : MEM_DDR3; dimm = csrow->channels[0]->dimm; @@ -263,7 +236,6 @@ static int init_csrows(struct mem_ctl_info *mci) static int aspeed_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; struct edac_mc_layer layers[2]; struct mem_ctl_info *mci; void __iomem *regs; @@ -274,13 +246,11 @@ static int aspeed_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); - aspeed_regmap = devm_regmap_init(dev, NULL, (__force void *)regs, - &aspeed_regmap_config); - if (IS_ERR(aspeed_regmap)) - return PTR_ERR(aspeed_regmap); + scoped_guard(raw_spinlock_irqsave, &aspeed_lock) + aspeed_regs = regs; /* bail out if ECC mode is not configured */ - regmap_read(aspeed_regmap, ASPEED_MCR_CONF, ®04); + reg04 = readl(regs + ASPEED_MCR_CONF); if (!(reg04 & ASPEED_MCR_CONF_ECC)) { dev_err(&pdev->dev, "ECC mode is not configured in u-boot\n"); return -EPERM; @@ -347,8 +317,7 @@ static void aspeed_remove(struct platform_device *pdev) int irq; /* disable interrupts */ - regmap_update_bits(aspeed_regmap, ASPEED_MCR_INTR_CTRL, - ASPEED_MCR_INTR_CTRL_ENABLE, 0); + aspeed_set_irq(false); irq = platform_get_irq(pdev, 0); WARN_ON(irq < 0); From patchwork Mon Aug 24 02:42:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290645 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4832-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFJ1HXrz1xwG for ; Mon, 24 Aug 2026 12:43:00 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwFD4HC6z2y8G; Mon, 24 Aug 2026 12:42:56 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539376; cv=none; b=T/yTwktHvAFXfsMhCEbTOmAZvaz/oKkeFvQHEHCzcAxZlQUkZLzr2FMHb4BTSbmDQC1phF1F1XGMzw6nlvFVebENxB5urYjBZF6dS9CWOjeQJ9bvF8v/2icm5ZBTv6S0jEjAOdHRF5Vk7V1luFmAsfoZIpH/KUcjE/RZvcKMO0a52iPTyVLU0CypPwS9qorOSiKuQxWTW+eDLUdG1Pcrw11covjds2DdxUprRRVCxaW57pn1HkYpUD1WBpx4JGZI6gQKYJng+xTw/wnX9X+xOIe/U9ZUBfkF5AHEmtGG/Qs1WkCWJV9g/xbWpI80cLvLxJcYtN5eaJw88oSM1EpjZw== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539376; c=relaxed/relaxed; bh=a1g4cFM2WSPo1E46t/j2LwC9w7NZQoGrUjOI+UYrux0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=ZgBnPvK/5ggfnMknMJyFe/I+aCUZUyuZbNjganOGgyiEPUtTx04rMPCOfywmRuQsFKbtmzmbqxw9kT3xXZQXwBXD5/NWDvpElgHrH4kRnz1U2GcZFJyRQ9lsRC0e1+bdtZfH3IlZc0IG8B4T3zukUi+0ynOo1pODAB/Lsxjp8hk7cJFQpJ/fqf2k21bXnEgV5UKJwWHlubTP+R1Z1MHry8pZMpbnnzB0E+N/GDzWJVFb5nHo3KTvIrALmGzPFiC0fs1X+UHZcx5fZ8kHSaWglb38IAlkW4Oz8dJ23FHgw84WMyg19HGM30P3cwoxb/wC8EqG64tkWMyzzxXzOjBokA== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwFC43N8z2xmk for ; Mon, 24 Aug 2026 12:42:55 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:30 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:30 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:34 +0800 Subject: [PATCH v2 7/8] EDAC/aspeed: Abstract SoC differences behind chip data X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-7-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=12030; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=9GcVj2fdxxCTsPwP9/o+MgofFZHMPAKymQnxcoTT3v0=; b=c/OnQKprV1QP9PTzVx+YeuvAxi0JKRV7IL7evjt5tyyVcLaP7vxt9fmuVPwlCVtxDSXMVENgD KS/plaRXDpsD0dAAoXy/ud1vOs7c79JCNHZM2H4o0j80/M1B56/H8IW X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org The driver hard-codes the AST2400/2500/2600 register layout, ECC and DRAM-type bits, memory types and write-protection key. Abstract these SoC-specific details behind a per-SoC struct aspeed_edac_chip selected by the compatible, and move the per-instance state (register base, lock) into mci->pvt_info instead of globals, so controller variants that differ in these details can be added as table data. Only the AST2400 and AST2500 key-protect the interrupt control register (MCR50); the AST2600 does not. Gate the unlock/relock on the chip carrying a protection key and split the shared entry into keyed (AST2400/2500) and unkeyed (AST2600) variants, so the AST2600 no longer performs the unnecessary unlock. Tested on an AST2600: A correctable error was injected from the console by unlocking the controller and writing its ECC error inject test register: # mw 1e6e0000 fc600309 # mw 1e6e00b0 81 EDAC MC0: 1 CE address(es) not available on mc#0csrow#0channel#0 (csrow:0 channel:0 page:0x0 offset:0x0 grain:16 syndrome:0x0) EDAC MC0: 1 CE on mc#0csrow#0channel#0 (csrow:0 channel:0 page:0x8a543 offset:0xec0 grain:16 syndrome:0x0) Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ryan Chen --- Changes in v2: - Carry over the irqsave lock acquisition in init_csrows() and the dev_dbg() moved out of the raw_spinlock critical section. - Store the interrupt number in struct aspeed_edac so that aspeed_remove() can free the interrupt without looking it up again. --- drivers/edac/aspeed_edac.c | 163 +++++++++++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 49 deletions(-) diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 26d2c456cc0d..e88d9d2646de 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -3,12 +3,14 @@ * Copyright 2018, 2019 Cisco Systems */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -30,8 +32,23 @@ #define ASPEED_MCR_INTR_CTRL_CNT_UNREC GENMASK(15, 12) #define ASPEED_MCR_INTR_CTRL_ENABLE (BIT(0) | BIT(1)) -static DEFINE_RAW_SPINLOCK(aspeed_lock); -static void __iomem *aspeed_regs __guarded_by(&aspeed_lock); +struct aspeed_edac_chip { + unsigned int conf_reg; + u32 conf_ecc; + u32 conf_dram_type; + enum mem_type dram_type[2]; + unsigned long mtype_cap; + unsigned int prot_reg; + u32 prot_key; +}; + +struct aspeed_edac { + raw_spinlock_t lock; + + void __iomem *regs __guarded_by(&lock); + const struct aspeed_edac_chip *chip; + int irq; +}; static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) { @@ -96,37 +113,54 @@ static void count_un_rec(struct mem_ctl_info *mci, u8 un_rec_cnt, } } -static irqreturn_t mcr_isr(int irq, void *arg) +static void aspeed_mcr_irq_update_enter(struct aspeed_edac *priv) + __must_hold(&priv->lock) +{ + if (priv->chip->prot_key) + writel(priv->chip->prot_key, priv->regs + priv->chip->prot_reg); +} + +static void aspeed_mcr_irq_update_exit(struct aspeed_edac *priv) + __must_hold(&priv->lock) +{ + if (priv->chip->prot_key) + writel(~priv->chip->prot_key, priv->regs + priv->chip->prot_reg); +} + +static irqreturn_t aspeed_mcr_isr(int irq, void *arg) { struct mem_ctl_info *mci = arg; u32 rec_addr, un_rec_addr; + struct aspeed_edac *priv; u8 rec_cnt, un_rec_cnt; u32 reg50; - scoped_guard(raw_spinlock, &aspeed_lock) { - reg50 = readl(aspeed_regs + ASPEED_MCR_INTR_CTRL); - un_rec_addr = readl(aspeed_regs + ASPEED_MCR_ADDR_UNREC); - rec_addr = readl(aspeed_regs + ASPEED_MCR_ADDR_REC); + priv = mci->pvt_info; + + scoped_guard(raw_spinlock, &priv->lock) { + reg50 = readl(priv->regs + ASPEED_MCR_INTR_CTRL); + un_rec_addr = readl(priv->regs + ASPEED_MCR_ADDR_UNREC); + rec_addr = readl(priv->regs + ASPEED_MCR_ADDR_REC); /* * Clearing the counters needs a set-then-clear of CLEAR. The * counter and interrupt flag fields are read-only, so writing * back the values read above leaves them unaffected. */ - writel(ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); + aspeed_mcr_irq_update_enter(priv); writel(reg50 | ASPEED_MCR_INTR_CTRL_CLEAR, - aspeed_regs + ASPEED_MCR_INTR_CTRL); + priv->regs + ASPEED_MCR_INTR_CTRL); writel(reg50 & ~ASPEED_MCR_INTR_CTRL_CLEAR, - aspeed_regs + ASPEED_MCR_INTR_CTRL); - writel(~ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); + priv->regs + ASPEED_MCR_INTR_CTRL); + aspeed_mcr_irq_update_exit(priv); } dev_dbg(mci->pdev, "received edac interrupt w/ mcr register 50: 0x%x\n", reg50); /* collect data about recoverable and unrecoverable errors */ - rec_cnt = (reg50 & ASPEED_MCR_INTR_CTRL_CNT_REC) >> 16; - un_rec_cnt = (reg50 & ASPEED_MCR_INTR_CTRL_CNT_UNREC) >> 12; + rec_cnt = FIELD_GET(ASPEED_MCR_INTR_CTRL_CNT_REC, reg50); + un_rec_cnt = FIELD_GET(ASPEED_MCR_INTR_CTRL_CNT_UNREC, reg50); dev_dbg(mci->pdev, "%d recoverable interrupts and %d unrecoverable interrupts\n", rec_cnt, un_rec_cnt); @@ -136,35 +170,36 @@ static irqreturn_t mcr_isr(int irq, void *arg) count_un_rec(mci, un_rec_cnt, un_rec_addr); if (!rec_cnt && !un_rec_cnt) - dev_dbg(mci->pdev, "received edac interrupt, but did not find any ECC counters\n"); + dev_dbg_ratelimited(mci->pdev, "received edac interrupt, but did not find any ECC counters\n"); - scoped_guard(raw_spinlock, &aspeed_lock) - reg50 = readl(aspeed_regs + ASPEED_MCR_INTR_CTRL); + scoped_guard(raw_spinlock, &priv->lock) + reg50 = readl(priv->regs + ASPEED_MCR_INTR_CTRL); dev_dbg(mci->pdev, "edac interrupt handled. mcr reg 50 is now: 0x%x\n", reg50); return IRQ_HANDLED; } -static void aspeed_set_irq(bool enable) +static void aspeed_set_irq(struct aspeed_edac *priv, bool enable) { u32 val; - guard(raw_spinlock_irqsave)(&aspeed_lock); + guard(raw_spinlock_irqsave)(&priv->lock); - val = readl(aspeed_regs + ASPEED_MCR_INTR_CTRL); + val = readl(priv->regs + ASPEED_MCR_INTR_CTRL); if (enable) val |= ASPEED_MCR_INTR_CTRL_ENABLE; else val &= ~ASPEED_MCR_INTR_CTRL_ENABLE; - writel(ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); - writel(val, aspeed_regs + ASPEED_MCR_INTR_CTRL); - writel(~ASPEED_MCR_PROT_PASSWD, aspeed_regs + ASPEED_MCR_PROT); + aspeed_mcr_irq_update_enter(priv); + writel(val, priv->regs + ASPEED_MCR_INTR_CTRL); + aspeed_mcr_irq_update_exit(priv); } -static int config_irq(void *ctx, struct platform_device *pdev) +static int config_irq(struct mem_ctl_info *mci, struct platform_device *pdev) { + struct aspeed_edac *priv = mci->pvt_info; int irq; int rc; @@ -174,13 +209,15 @@ static int config_irq(void *ctx, struct platform_device *pdev) if (irq < 0) return irq; - rc = devm_request_irq(&pdev->dev, irq, mcr_isr, IRQF_TRIGGER_HIGH, - DRV_NAME, ctx); + rc = devm_request_irq(&pdev->dev, irq, aspeed_mcr_isr, IRQF_TRIGGER_HIGH, + DRV_NAME, mci); if (rc) return rc; + priv->irq = irq; + /* enable interrupts */ - aspeed_set_irq(true); + aspeed_set_irq(priv, true); return 0; } @@ -188,11 +225,13 @@ static int config_irq(void *ctx, struct platform_device *pdev) static int init_csrows(struct mem_ctl_info *mci) { struct csrow_info *csrow = mci->csrows[0]; - u32 nr_pages, dram_type; - struct dimm_info *dimm; + struct aspeed_edac *priv = mci->pvt_info; struct device_node *np; + struct dimm_info *dimm; struct resource r; - u32 reg04; + unsigned int type; + u32 nr_pages; + u32 conf; int rc; /* retrieve info about physical memory from device tree */ @@ -218,12 +257,12 @@ static int init_csrows(struct mem_ctl_info *mci) nr_pages = resource_size(&r) >> PAGE_SHIFT; csrow->last_page = csrow->first_page + nr_pages - 1; - scoped_guard(raw_spinlock_irqsave, &aspeed_lock) - reg04 = readl(aspeed_regs + ASPEED_MCR_CONF); - dram_type = (reg04 & ASPEED_MCR_CONF_DRAM_TYPE) ? MEM_DDR4 : MEM_DDR3; + scoped_guard(raw_spinlock_irqsave, &priv->lock) + conf = readl(priv->regs + priv->chip->conf_reg); + type = field_get(priv->chip->conf_dram_type, conf); dimm = csrow->channels[0]->dimm; - dimm->mtype = dram_type; + dimm->mtype = priv->chip->dram_type[type]; dimm->edac_mode = EDAC_SECDED; dimm->nr_pages = nr_pages / csrow->nr_channels; dimm->grain = 16; @@ -236,22 +275,26 @@ static int init_csrows(struct mem_ctl_info *mci) static int aspeed_probe(struct platform_device *pdev) { + const struct aspeed_edac_chip *chip; + struct device *dev = &pdev->dev; struct edac_mc_layer layers[2]; + struct aspeed_edac *priv; struct mem_ctl_info *mci; void __iomem *regs; - u32 reg04; + u32 conf; int rc; + chip = of_device_get_match_data(dev); + if (!chip) + return -EINVAL; + regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(regs)) return PTR_ERR(regs); - scoped_guard(raw_spinlock_irqsave, &aspeed_lock) - aspeed_regs = regs; - /* bail out if ECC mode is not configured */ - reg04 = readl(regs + ASPEED_MCR_CONF); - if (!(reg04 & ASPEED_MCR_CONF_ECC)) { + conf = readl(regs + chip->conf_reg); + if (!field_get(chip->conf_ecc, conf)) { dev_err(&pdev->dev, "ECC mode is not configured in u-boot\n"); return -EPERM; } @@ -266,12 +309,17 @@ static int aspeed_probe(struct platform_device *pdev) layers[1].size = 1; layers[1].is_virt_csrow = false; - mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0); + mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*priv)); if (!mci) return -ENOMEM; + priv = mci->pvt_info; + priv->chip = chip; + scoped_guard(raw_spinlock_init, &priv->lock) + priv->regs = regs; + mci->pdev = &pdev->dev; - mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4; + mci->mtype_cap = chip->mtype_cap; mci->edac_ctl_cap = EDAC_FLAG_SECDED; mci->edac_cap = EDAC_FLAG_SECDED; mci->scrub_cap = SCRUB_FLAG_HW_SRC; @@ -314,24 +362,41 @@ static int aspeed_probe(struct platform_device *pdev) static void aspeed_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); - int irq; + struct aspeed_edac *priv = mci->pvt_info; /* disable interrupts */ - aspeed_set_irq(false); + aspeed_set_irq(priv, false); - irq = platform_get_irq(pdev, 0); - WARN_ON(irq < 0); - devm_free_irq(&pdev->dev, irq, mci); + devm_free_irq(&pdev->dev, priv->irq, mci); /* free resources */ edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); } +static const struct aspeed_edac_chip ast2400_edac = { + .conf_reg = ASPEED_MCR_CONF, + .conf_ecc = ASPEED_MCR_CONF_ECC, + .conf_dram_type = ASPEED_MCR_CONF_DRAM_TYPE, + .dram_type = { MEM_DDR3, MEM_DDR4 }, + .mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4, + .prot_reg = ASPEED_MCR_PROT, + .prot_key = ASPEED_MCR_PROT_PASSWD, +}; + +/* The AST2600 does not key-protect the interrupt control register (MCR50). */ +static const struct aspeed_edac_chip ast2600_edac = { + .conf_reg = ASPEED_MCR_CONF, + .conf_ecc = ASPEED_MCR_CONF_ECC, + .conf_dram_type = ASPEED_MCR_CONF_DRAM_TYPE, + .dram_type = { MEM_DDR3, MEM_DDR4 }, + .mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4, +}; + static const struct of_device_id aspeed_of_match[] = { - { .compatible = "aspeed,ast2400-sdram-edac" }, - { .compatible = "aspeed,ast2500-sdram-edac" }, - { .compatible = "aspeed,ast2600-sdram-edac" }, + { .compatible = "aspeed,ast2400-sdram-edac", .data = &ast2400_edac }, + { .compatible = "aspeed,ast2500-sdram-edac", .data = &ast2400_edac }, + { .compatible = "aspeed,ast2600-sdram-edac", .data = &ast2600_edac }, {}, }; From patchwork Mon Aug 24 02:42:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ryan Chen X-Patchwork-Id: 2290646 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=112.213.38.117; helo=lists.ozlabs.org; envelope-from=linux-aspeed+bounces-4833-incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=patchwork.ozlabs.org) Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4hSwFK1Q8Cz1xwG for ; Mon, 24 Aug 2026 12:43:01 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [127.0.0.1]) by lists.ozlabs.org (Postfix) with ESMTP id 4hSwFG0skBz2y8c; Mon, 24 Aug 2026 12:42:58 +1000 (AEST) X-Original-To: linux-aspeed@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; arc=none smtp.remote-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539378; cv=none; b=ATNw0bpYHOnTTtNRXig7EpIZKjqSnPikF8BfnHiSB4Zv/GqiTVefknwWIhyrFzkIV8K9Yb8oi4tCjris7L8aCEAlmDArOLkPzSmRQ1uFJeig9Ha4EVES8Fa0Oa7wCECZ3VdJCy4ssLliOMp+8EQEoFpYE4AIA/LZ+fd8V1/eo3QJDY03gBk+lOxKS0LfkHhBQQ71HzNTHtZxL46zPAIgDP5yGeLiaO99mjV1ORHDFlIv80b1yfUELAkpDBN6ZoUD7ZbsbCkJwk3Ip4ozRBjIuDmRDfD/gsFI8L2vzKzXyOOFoXtB3XVvr3aFEJu8FtW7Ip0TTTnmFMabOjVjoF6P+A== ARC-Message-Signature: i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1787539378; c=relaxed/relaxed; bh=tPpi/6PIYbl3odSZFYRo6w14+egDnPip6xsURGiMkrg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-ID:References: In-Reply-To:To:CC; b=G61SxbJKNW/GKls89IdoEyHbgBONB8Jtm45Wfh797WhcUwe2Yt5wgMxAft6/TmuEf1AAHTMFeMHzrTToK3uzKisbm6++FZfneDUyc7v0wqSvEVtrTn0BPSXt4YjvE346KzL4vM6nDSpcgsBUL7yOg/xrECCQx1OFKYZa88ksEdBiyuIT99i3YxjadfkwjWQNM/CrCUWKU/w/18Kaq8fEl2OlADm/Nd3bJTLgQTsMzJV4ZeeG6tM5CawnBRjp1TbVPPDZ/LRvvE0CZ4Bv6uKrvcRwR/yMftZhfLkmj8n8wCfUJhC/hr5axWEM5ZRiWMi1XYSs+3S89ZLlkcQspiKRrQ== ARC-Authentication-Results: i=1; lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) smtp.mailfrom=aspeedtech.com Authentication-Results: lists.ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=aspeedtech.com (client-ip=211.20.114.72; helo=twmbx01.aspeedtech.com; envelope-from=ryan_chen@aspeedtech.com; receiver=lists.ozlabs.org) Received: from twmbx01.aspeedtech.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4hSwFD5vRzz2xmk for ; Mon, 24 Aug 2026 12:42:56 +1000 (AEST) Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1748.10; Mon, 24 Aug 2026 10:42:30 +0800 Received: from [127.0.1.1] (192.168.10.13) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1748.10 via Frontend Transport; Mon, 24 Aug 2026 10:42:30 +0800 From: Ryan Chen Date: Mon, 24 Aug 2026 10:42:35 +0800 Subject: [PATCH v2 8/8] EDAC/aspeed: Add AST2700 support X-Mailing-List: linux-aspeed@lists.ozlabs.org List-Id: List-Help: List-Owner: List-Post: List-Archive: , List-Subscribe: , , List-Unsubscribe: Precedence: list MIME-Version: 1.0 Message-ID: <20260824-edac-v2-8-c8d8bb693586@aspeedtech.com> References: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> In-Reply-To: <20260824-edac-v2-0-c8d8bb693586@aspeedtech.com> To: Stefan Schaeckeler , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Joel Stanley , Andrew Jeffery , Borislav Petkov , Tony Luck CC: , , , , , Ryan Chen X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1787539349; l=11489; i=ryan_chen@aspeedtech.com; s=20251126; h=from:subject:message-id; bh=HlelczrZse4itqbntkw1AflaRc+t0N11SCs7ovp7nzw=; b=LNccIVppdqVKTXHSnMaJ1c1YboG4AOpHa0LIPmIpA2GiOjZIZunNiFehQVzos/URnOHZsUYH8 eArPWn00qQcBrxCePZvWxFGHZM47cHj6RRS5u/FpeMzUsGrFDquD4RD X-Developer-Key: i=ryan_chen@aspeedtech.com; a=ed25519; pk=Xe73xY6tcnkuRjjbVAB/oU30KdB3FvG4nuJuILj7ZVc= X-Spam-Status: No, score=0.0 required=5.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org Add SDRAM ECC reporting for the Aspeed AST2700. Its DRAMC has a different register layout, a split interrupt status/clear/mask scheme, DDR4/DDR5 memory and interrupt registers that are not key-protected. Its interrupt status/clear and enable sequences differ from the earlier SoCs, so add per-chip isr() and set_irq() hooks and route the devm_request_irq() and enable/disable paths through them, keeping the existing AST2400/2500/2600 behaviour under the shared aspeed_mcr_isr()/aspeed_set_irq(). Unlike the earlier SoCs it records a single failure address shared by both error types, so extend the shared count_rec()/count_un_rec() helpers with a have_addr flag to report an error without an address (existing SoCs pass have_addr = true, unchanged) and widen their address argument to phys_addr_t as the AST2700 address can exceed 32 bits. Tested on an AST2700: A correctable error was injected from the console by unlocking the controller and writing its ECC error inject test register: # mw 12c00000 1688a8a8 # mw 12c00080 31 EDAC MC0: 1 CE on mc#0csrow#0channel#0 (csrow:0 channel:0 page:0x40f6da offset:0xdb0 grain:16 syndrome:0x0) Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ryan Chen --- Changes in v2: - Return IRQ_NONE from ast2700_dramc_isr() when no ECC interrupt status bit is set. The handler clears only the ECC bits, so unconditionally claiming the interrupt could livelock the level-triggered line if another DRAMC source was left unmasked. - Add AST2700_INT_ECC for the pair of ECC interrupt bits, now used by both the handler and the enable path. - Expand the enable/disable ternary in ast2700_set_irq() into if/else, matching the shape of aspeed_set_irq(). - Pass struct aspeed_edac to the set_irq() hooks instead of struct mem_ctl_info, which the callees only used to reach pvt_info. --- drivers/edac/aspeed_edac.c | 161 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 26 deletions(-) diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index e88d9d2646de..88b7f5ff3727 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -32,6 +32,23 @@ #define ASPEED_MCR_INTR_CTRL_CNT_UNREC GENMASK(15, 12) #define ASPEED_MCR_INTR_CTRL_ENABLE (BIT(0) | BIT(1)) +#define AST2700_INT_STS 0x04 +#define AST2700_INT_CLR 0x08 +#define AST2700_INT_MASK 0x0c +#define AST2700_INT_ECC_RECOVERABLE BIT(5) +#define AST2700_INT_ECC_UNRECOVERABLE BIT(4) +#define AST2700_INT_ECC (AST2700_INT_ECC_RECOVERABLE | \ + AST2700_INT_ECC_UNRECOVERABLE) +#define AST2700_MCFG 0x10 +#define AST2700_MCFG_ECC BIT(6) +#define AST2700_MCFG_DRAM_TYPE BIT(0) /* 0=DDR4, 1=DDR5 */ +#define AST2700_ECC_STS 0x78 +#define AST2700_ECC_REC_CNT GENMASK(15, 8) +#define AST2700_ECC_UNREC_CNT GENMASK(7, 0) +#define AST2700_ECC_FAIL_ADDR 0x7c + +struct aspeed_edac; + struct aspeed_edac_chip { unsigned int conf_reg; u32 conf_ecc; @@ -40,6 +57,8 @@ struct aspeed_edac_chip { unsigned long mtype_cap; unsigned int prot_reg; u32 prot_key; + irqreturn_t (*isr)(int irq, void *arg); + void (*set_irq)(struct aspeed_edac *priv, bool enable); }; struct aspeed_edac { @@ -50,26 +69,34 @@ struct aspeed_edac { int irq; }; -static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) +static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, phys_addr_t rec_addr, + bool have_addr) { struct csrow_info *csrow = mci->csrows[0]; - u32 page, offset, syndrome; + unsigned long page, offset, syndrome; if (!rec_cnt) return; - /* report first few errors (if there are) */ - /* note: no addresses are recorded */ - if (rec_cnt > 1) { + /* + * Report the errors whose address is not recorded: all of them when + * no address is available, otherwise all but the last one (reported + * with its address below). + */ + if (rec_cnt > 1 || !have_addr) { /* page, offset and syndrome are not available */ page = 0; offset = 0; syndrome = 0; - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, rec_cnt-1, + edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, + have_addr ? rec_cnt - 1 : rec_cnt, page, offset, syndrome, 0, 0, -1, "address(es) not available", ""); } + if (!have_addr) + return; + /* report last error */ /* note: rec_addr is the last recoverable error addr */ page = rec_addr >> PAGE_SHIFT; @@ -82,32 +109,34 @@ static void count_rec(struct mem_ctl_info *mci, u8 rec_cnt, u32 rec_addr) } static void count_un_rec(struct mem_ctl_info *mci, u8 un_rec_cnt, - u32 un_rec_addr) + phys_addr_t un_rec_addr, bool have_addr) { struct csrow_info *csrow = mci->csrows[0]; - u32 page, offset, syndrome; + unsigned long page, offset, syndrome; if (!un_rec_cnt) return; - /* report 1. error */ - /* note: un_rec_addr is the first unrecoverable error addr */ - page = un_rec_addr >> PAGE_SHIFT; - offset = un_rec_addr & ~PAGE_MASK; - /* syndrome is not available */ - syndrome = 0; - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - csrow->first_page + page, offset, syndrome, - 0, 0, -1, "", ""); + /* report the first error with its address when one is available */ + if (have_addr) { + /* note: un_rec_addr is the first unrecoverable error addr */ + page = un_rec_addr >> PAGE_SHIFT; + offset = un_rec_addr & ~PAGE_MASK; + /* syndrome is not available */ + syndrome = 0; + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, + csrow->first_page + page, offset, syndrome, + 0, 0, -1, "", ""); + } - /* report further errors (if there are) */ - /* note: no addresses are recorded */ - if (un_rec_cnt > 1) { + /* report the remaining errors without a recorded address */ + if (un_rec_cnt > 1 || !have_addr) { /* page, offset and syndrome are not available */ page = 0; offset = 0; syndrome = 0; - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, un_rec_cnt-1, + edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, + have_addr ? un_rec_cnt - 1 : un_rec_cnt, page, offset, syndrome, 0, 0, -1, "address(es) not available", ""); } @@ -166,8 +195,8 @@ static irqreturn_t aspeed_mcr_isr(int irq, void *arg) rec_cnt, un_rec_cnt); /* process recoverable and unrecoverable errors */ - count_rec(mci, rec_cnt, rec_addr); - count_un_rec(mci, un_rec_cnt, un_rec_addr); + count_rec(mci, rec_cnt, rec_addr, true); + count_un_rec(mci, un_rec_cnt, un_rec_addr, true); if (!rec_cnt && !un_rec_cnt) dev_dbg_ratelimited(mci->pdev, "received edac interrupt, but did not find any ECC counters\n"); @@ -180,6 +209,54 @@ static irqreturn_t aspeed_mcr_isr(int irq, void *arg) return IRQ_HANDLED; } +static irqreturn_t ast2700_dramc_isr(int irq, void *arg) +{ + u32 int_sts, ecc_sts, fail_addr; + struct mem_ctl_info *mci = arg; + struct aspeed_edac *priv; + u8 rec_cnt, un_rec_cnt; + phys_addr_t addr; + + priv = mci->pvt_info; + + scoped_guard(raw_spinlock, &priv->lock) { + int_sts = readl(priv->regs + AST2700_INT_STS); + if (!(int_sts & AST2700_INT_ECC)) + return IRQ_NONE; + + ecc_sts = readl(priv->regs + AST2700_ECC_STS); + fail_addr = readl(priv->regs + AST2700_ECC_FAIL_ADDR); + + /* the interrupt registers are not key-protected; clear only ECC */ + writel(int_sts & AST2700_INT_ECC, priv->regs + AST2700_INT_CLR); + } + + rec_cnt = FIELD_GET(AST2700_ECC_REC_CNT, ecc_sts); + un_rec_cnt = FIELD_GET(AST2700_ECC_UNREC_CNT, ecc_sts); + + /* the register holds address bits [35:4], in units of 16 bytes */ + addr = (phys_addr_t)fail_addr << 4; + + /* + * The controller records only the address of the latest failure, + * shared by both error types. When only one type occurred it owns + * that address; when both occurred attribute it to the uncorrectable + * error and report the corrected ones without an address. + */ + if (un_rec_cnt && !rec_cnt) { + count_un_rec(mci, un_rec_cnt, addr, true); + } else if (!un_rec_cnt && rec_cnt) { + count_rec(mci, rec_cnt, addr, true); + } else if (un_rec_cnt && rec_cnt) { + count_un_rec(mci, un_rec_cnt, addr, true); + count_rec(mci, rec_cnt, 0, false); + } else { + dev_dbg_ratelimited(mci->pdev, "received interrupt with no ECC counters set\n"); + } + + return IRQ_HANDLED; +} + static void aspeed_set_irq(struct aspeed_edac *priv, bool enable) { u32 val; @@ -197,6 +274,22 @@ static void aspeed_set_irq(struct aspeed_edac *priv, bool enable) aspeed_mcr_irq_update_exit(priv); } +static void ast2700_set_irq(struct aspeed_edac *priv, bool enable) +{ + u32 val; + + guard(raw_spinlock_irqsave)(&priv->lock); + + /* interrupts are enabled by clearing their mask bits */ + val = readl(priv->regs + AST2700_INT_MASK); + if (enable) + val &= ~AST2700_INT_ECC; + else + val |= AST2700_INT_ECC; + + writel(val, priv->regs + AST2700_INT_MASK); +} + static int config_irq(struct mem_ctl_info *mci, struct platform_device *pdev) { struct aspeed_edac *priv = mci->pvt_info; @@ -209,7 +302,7 @@ static int config_irq(struct mem_ctl_info *mci, struct platform_device *pdev) if (irq < 0) return irq; - rc = devm_request_irq(&pdev->dev, irq, aspeed_mcr_isr, IRQF_TRIGGER_HIGH, + rc = devm_request_irq(&pdev->dev, irq, priv->chip->isr, IRQF_TRIGGER_HIGH, DRV_NAME, mci); if (rc) return rc; @@ -217,7 +310,7 @@ static int config_irq(struct mem_ctl_info *mci, struct platform_device *pdev) priv->irq = irq; /* enable interrupts */ - aspeed_set_irq(priv, true); + priv->chip->set_irq(priv, true); return 0; } @@ -365,7 +458,7 @@ static void aspeed_remove(struct platform_device *pdev) struct aspeed_edac *priv = mci->pvt_info; /* disable interrupts */ - aspeed_set_irq(priv, false); + priv->chip->set_irq(priv, false); devm_free_irq(&pdev->dev, priv->irq, mci); @@ -382,6 +475,8 @@ static const struct aspeed_edac_chip ast2400_edac = { .mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4, .prot_reg = ASPEED_MCR_PROT, .prot_key = ASPEED_MCR_PROT_PASSWD, + .isr = aspeed_mcr_isr, + .set_irq = aspeed_set_irq, }; /* The AST2600 does not key-protect the interrupt control register (MCR50). */ @@ -391,12 +486,26 @@ static const struct aspeed_edac_chip ast2600_edac = { .conf_dram_type = ASPEED_MCR_CONF_DRAM_TYPE, .dram_type = { MEM_DDR3, MEM_DDR4 }, .mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4, + .isr = aspeed_mcr_isr, + .set_irq = aspeed_set_irq, +}; + +/* The AST2700 interrupt registers are not key-protected either. */ +static const struct aspeed_edac_chip ast2700_edac = { + .conf_reg = AST2700_MCFG, + .conf_ecc = AST2700_MCFG_ECC, + .conf_dram_type = AST2700_MCFG_DRAM_TYPE, + .dram_type = { MEM_DDR4, MEM_DDR5 }, + .mtype_cap = MEM_FLAG_DDR4 | MEM_FLAG_DDR5, + .isr = ast2700_dramc_isr, + .set_irq = ast2700_set_irq, }; static const struct of_device_id aspeed_of_match[] = { { .compatible = "aspeed,ast2400-sdram-edac", .data = &ast2400_edac }, { .compatible = "aspeed,ast2500-sdram-edac", .data = &ast2400_edac }, { .compatible = "aspeed,ast2600-sdram-edac", .data = &ast2600_edac }, + { .compatible = "aspeed,ast2700-sdram-edac", .data = &ast2700_edac }, {}, };