From patchwork Tue Feb 14 23:34:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Fainelli X-Patchwork-Id: 13141019 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 260EEC61DA4 for ; Tue, 14 Feb 2023 23:35:59 +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=3cdh++SZ/zA4sjZkGhJvtJjHJJ/wUc6HPcJ/XBfBaho=; b=hstw3sQevkTYko TIWB9T2DIRU+nE5VByyHw4YNlz4wD8Uo/UF8cO0npS+kYhlMxKxdUbGgNLRDRc3BhO1aK4nH5qBvM /iz2Z9yGWNKiEQtjWkIe6sdqVD7P3vmfRokJjoNaQSiR9FFClyfJllhkayUW4F9kSnA5PkH0JD9vG osfYEJob/G/2g0zRh5XHuVtoufX+ReRSRWIO3sKsbcgmwTxSsGFyALgRMVjN2infuZqm0SyVnH/7a lzipACl9ezYCL8mmG/s+xWHPGieioztpKhWTrtgXIg6hyqyJSwdkIsuz1AmN4Kg/N67OFxTniDVbA MyelEedCuwN22/13hO3Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pS4pD-003uPr-Sm; Tue, 14 Feb 2023 23:35:04 +0000 Received: from mail-pj1-x1035.google.com ([2607:f8b0:4864:20::1035]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pS4or-003uIQ-QT for linux-arm-kernel@lists.infradead.org; Tue, 14 Feb 2023 23:34:44 +0000 Received: by mail-pj1-x1035.google.com with SMTP id bg2so7293875pjb.4 for ; Tue, 14 Feb 2023 15:34:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; 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=SyylP0dLgQ4asCxngY/+BtyC8fT6IgNch9KD6tsWn/k=; b=ZJWgdgdeDcALyzNsrzBmfXelgCjE+0JdPXLeH90B+rr8GyPVpeoxYPCZRgrNv5WI6e hSUDXiyA6P+WCdgvQhhc+L33e9c2GNzrTWBcRXo3xgiAjI63oVTl+xG4VyOimslwSvjU t4yVgP6xYmF8otZPDjHs+YLNzAzLbcyu00X9IgJmwPZMZL6AYFjBh5fTIFWRljnvu1zw /EiiNn/0JaLuo5Ri0khUcyZL7kn4JgQ9khORK9qp5I/NF1Zz0FJKd6HC5ZnNFZKYRTre PdOshuv3UAmAYo7157ru/5SZT0jolOvkX70qQhP0yGyzQuIdQ680ndqnOQmmNqm0F92/ oggQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=SyylP0dLgQ4asCxngY/+BtyC8fT6IgNch9KD6tsWn/k=; b=Z/nRCX0lw9X9uMt7wBZHhAgWcw84M6QRXKGVChXiEfCG1W7nnsSjFYmDsaKjLaFyRF cavt0ME6rBWxI6PbFMK0PVo6AgZU5aBHOtzQ+VJeDHW1tiOLkVWTORfejWD0mNEY1qqf CjruQl5sfbZS1ZuEekj1bdTlAAj3xD1a+V1O0Rfa4CUx0HfneBGaQW/rFcRc6u3diQNv Zs/kLOKk6Wj6lstNqFbJU1Sw/ISv0DnBhd3ds+58cDBdyHNw57497bht8U5zW57uU3ea zChyZaQ5eA4hutlhozbj8Nzcl0sTNY29pVMFIUK8A8AMkE5pZu/wxTAnmjlnjnHpMbUq oH/Q== X-Gm-Message-State: AO0yUKXp2naInZGAweAxw6nzRMTgI8h62bGF6PzUuTlhbR5eVt2NTmKc NfipqgM4RdEmeWCVOilq+pEEpmGnGGdVeQ== X-Google-Smtp-Source: AK7set9gUgKFKTHPQ4vcB+yKpE8Sa0qQPAg6uGk1MQXwoJmPMzDWwyRmQ9Bvk5uGmNZuOOjv8WWpjQ== X-Received: by 2002:a17:903:1c9:b0:198:9f0c:a91 with SMTP id e9-20020a17090301c900b001989f0c0a91mr481784plh.20.1676417678335; Tue, 14 Feb 2023 15:34:38 -0800 (PST) Received: from fainelli-desktop.igp.broadcom.net ([192.19.223.252]) by smtp.gmail.com with ESMTPSA id f12-20020a170902684c00b001963a178dfcsm9434801pln.244.2023.02.14.15.34.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 14 Feb 2023 15:34:37 -0800 (PST) From: Florian Fainelli To: linux-arm-kernel@lists.infradead.org Cc: Florian Fainelli , Thomas Gleixner , Marc Zyngier , Oliver Upton , linux-kernel@vger.kernel.org (open list:IRQCHIP DRIVERS), Sudeep Holla , Broadcom internal kernel review list Subject: [PATCH 3/3] irqchip/gic-v3: Save and restore distributor and re-distributor Date: Tue, 14 Feb 2023 15:34:26 -0800 Message-Id: <20230214233426.2994501-4-f.fainelli@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230214233426.2994501-1-f.fainelli@gmail.com> References: <20230214233426.2994501-1-f.fainelli@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230214_153441_889017_FC2CE4CA X-CRM114-Status: GOOD ( 21.72 ) 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 On platforms implementing Suspend to RAM where the GIC loses power, we are not properly saving and restoring the GIC distributor and re-distributor registers thus leading to the system resuming without any functional interrupts. Add support for saving and restoring the GIC distributor and re-distributor in order to properly suspend and resume with a functional system. Signed-off-by: Florian Fainelli --- drivers/irqchip/irq-gic-v3.c | 258 +++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 4 + 2 files changed, 262 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 48b0e9aba27c..4caab61268d0 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,25 @@ struct gic_chip_data { bool has_rss; unsigned int ppi_nr; struct partition_desc **ppi_descs; +#ifdef CONFIG_CPU_PM + u32 *saved_spi_conf; + u64 *saved_spi_target; + u32 *saved_spi_enable; + u32 *saved_spi_active; + + u32 *saved_espi_conf; + u64 *saved_espi_target; + u32 *saved_espi_enable; + u32 *saved_espi_active; + + u32 saved_ppi_conf; + u32 saved_ppi_enable; + u32 saved_ppi_active; + + u32 *saved_eppi_conf; + u32 *saved_eppi_enable; + u32 *saved_eppi_active; +#endif }; static struct gic_chip_data gic_data __read_mostly; @@ -1371,6 +1391,143 @@ static int gic_retrigger(struct irq_data *data) } #ifdef CONFIG_CPU_PM +static void gic_rdist_save(void) +{ + struct gic_chip_data *gic = &gic_data; + void __iomem *rbase = gic_data_rdist_sgi_base(); + unsigned int i; + + gic->saved_ppi_conf = readl_relaxed(rbase + GICR_ICFGR0 + 4); + gic->saved_ppi_enable = readl_relaxed(rbase + GICR_ISENABLER0); + gic->saved_ppi_active = readl_relaxed(rbase + GICR_ICACTIVER0); + + for (i = 0; i < DIV_ROUND_UP(gic->ppi_nr - 16, 32); i++) { + gic->saved_eppi_conf[i] = + readl_relaxed(rbase + GICR_ICFGRnE + i * 4); + gic->saved_eppi_enable[i] = + readl_relaxed(rbase + GICR_ISENABLERnE + i * 4); + gic->saved_eppi_active[i] = + readl_relaxed(rbase + GICR_ICACTIVERnE + i * 4); + } +} + +static void gic_dist_save(void) +{ + struct gic_chip_data *gic = &gic_data; + void __iomem *base = gic_data.dist_base; + unsigned int i; + + /* Save the SPIs first */ + for (i = 2; i < DIV_ROUND_UP(GIC_LINE_NR, 16); i++) + gic->saved_spi_conf[i] = + readl_relaxed(base + GICD_ICFGR + i * 4); + + for (i = 32; i < GIC_LINE_NR; i++) + gic->saved_spi_target[i] = + readq_relaxed(base + GICD_IROUTER + i * 8); + + for (i = 1; i < DIV_ROUND_UP(GIC_LINE_NR, 32); i++) { + gic->saved_spi_enable[i] = + readl_relaxed(base + GICD_ISENABLER + i * 4); + gic->saved_spi_active[i] = + readl_relaxed(base + GICD_ISACTIVER + i * 4); + } + + /* Save the EPIs next */ + for (i = 0; i < DIV_ROUND_UP(GIC_ESPI_NR, 16); i++) + gic->saved_espi_conf[i] = + readl_relaxed(base + GICD_ICFGRnE + i * 4); + + for (i = 0; i < GIC_ESPI_NR; i++) + gic->saved_espi_target[i] = + readq_relaxed(base + GICD_IROUTERnE + i * 8); + + for (i = 0; i < DIV_ROUND_UP(GIC_ESPI_NR, 32); i++) { + gic->saved_espi_enable[i] = + readl_relaxed(base + GICD_ISENABLERnE + i * 4); + gic->saved_espi_active[i] = + readl_relaxed(base + GICD_ISACTIVERnE + i * 4); + } +} + +static void gic_rdist_restore(void) +{ + struct gic_chip_data *gic = &gic_data; + void __iomem *rbase = gic_data_rdist_sgi_base(); + unsigned int i; + + writel_relaxed(gic->saved_ppi_conf, rbase + GICR_ICFGR0 + 4); + writel_relaxed(gic->saved_ppi_enable, rbase + GICR_ISENABLER0); + writel_relaxed(gic->saved_ppi_active, rbase + GICR_ICACTIVER0); + + for (i = 0; i < DIV_ROUND_UP(gic->ppi_nr - 16, 32); i++) { + writel_relaxed(gic->saved_eppi_conf[i], + rbase + GICR_ICFGRnE + i * 4); + writel_relaxed(gic->saved_eppi_enable[i], + rbase + GICR_ISENABLERnE + i * 4); + writel_relaxed(gic->saved_eppi_active[i], + rbase + GICR_ICACTIVERnE + i * 4); + } +} + +static void gic_dist_restore(void) +{ + struct gic_chip_data *gic = &gic_data; + void __iomem *base = gic_data.dist_base; + unsigned int i; + + /* Ensure distributor is disabled */ + writel_relaxed(0, base + GICD_CTLR); + gic_dist_wait_for_rwp(); + + /* Configure SPIs as non-secure Group-1. */ + for (i = 32; i < GIC_LINE_NR; i += 32) + writel_relaxed(~0, base + GICD_IGROUPR + i / 8); + + /* Restore the SPIs */ + for (i = 2; i < DIV_ROUND_UP(GIC_LINE_NR, 16); i++) + writel_relaxed(gic->saved_spi_conf[i], + base + GICD_ICFGR + i * 4); + + for (i = 32; i < GIC_LINE_NR; i++) + writel_relaxed(gic->saved_spi_target[i], + base + GICD_IROUTER + i * 8); + + for (i = 1; i < DIV_ROUND_UP(GIC_LINE_NR, 32); i++) { + writel_relaxed(gic->saved_spi_enable[i], + base + GICD_ISENABLER + i * 4); + writel_relaxed(gic->saved_spi_active[i], + base + GICD_ISACTIVER + i * 4); + } + + /* Configure ESPIs as non-secure Group-1. */ + for (i = 0; i < GIC_ESPI_NR; i += 32) + writel_relaxed(~0U, base + GICD_IGROUPRnE + i / 8); + + /* Restore the ESPIs */ + for (i = 0; i < DIV_ROUND_UP(GIC_ESPI_NR, 16); i++) + writel_relaxed(gic->saved_espi_conf[i], + base + GICD_ICFGRnE + i * 4); + + for (i = 0; i < GIC_ESPI_NR; i++) + writeq_relaxed(gic->saved_espi_target[i], + base + GICD_IROUTERnE + i * 8); + + for (i = 0; i < DIV_ROUND_UP(GIC_ESPI_NR, 32); i++) { + writel_relaxed(gic->saved_espi_enable[i], + base + GICD_ISENABLERnE + i * 4); + writel_relaxed(gic->saved_espi_active[i], + base + GICD_ISACTIVERnE + i * 4); + } + + for (i = 0; i < GIC_ESPI_NR; i += 4) + writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i); + + /* Enable distributor with ARE, Group1 */ + writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, + base + GICD_CTLR); +} + static int gic_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd, void *v) { @@ -1380,12 +1537,20 @@ static int gic_cpu_pm_notifier(struct notifier_block *self, gic_write_grpen1(0); gic_enable_redist(false); } + gic_rdist_save(); + break; + case CPU_CLUSTER_PM_ENTER: + gic_dist_save(); break; case CPU_PM_EXIT: + gic_rdist_restore(); if (gic_dist_security_disabled()) gic_enable_redist(true); gic_cpu_sys_reg_init(); break; + case CPU_CLUSTER_PM_EXIT: + gic_dist_restore(); + break; } return NOTIFY_OK; @@ -1397,9 +1562,102 @@ static struct notifier_block gic_cpu_pm_notifier_block = { static int gic_cpu_pm_init(void) { + struct gic_chip_data *gic = &gic_data; + unsigned int spi_size = DIV_ROUND_UP(GIC_LINE_NR, 32); + unsigned int espi_size = DIV_ROUND_UP(GIC_ESPI_NR, 32); + unsigned int eppi_size = DIV_ROUND_UP(gic->ppi_nr - 16, 32); + + gic->saved_spi_conf = kcalloc(DIV_ROUND_UP(GIC_LINE_NR, 16), + sizeof(*gic->saved_spi_conf), + GFP_KERNEL); + if (WARN_ON(!gic->saved_spi_conf)) + return -ENOMEM; + + gic->saved_spi_target = kcalloc(GIC_LINE_NR, + sizeof(*gic->saved_spi_target), + GFP_KERNEL); + if (WARN_ON(!gic->saved_spi_target)) + goto out_free_spi_conf; + + gic->saved_spi_enable = kcalloc(spi_size, + sizeof(*gic->saved_spi_enable), + GFP_KERNEL); + if (WARN_ON(!gic->saved_spi_enable)) + goto out_free_spi_target; + + gic->saved_spi_active = kcalloc(spi_size, + sizeof(*gic->saved_spi_active), + GFP_KERNEL); + if (WARN_ON(!gic->saved_spi_active)) + goto out_free_spi_enable; + + gic->saved_espi_conf = kcalloc(DIV_ROUND_UP(GIC_ESPI_NR, 16), + sizeof(*gic->saved_espi_conf), + GFP_KERNEL); + if (WARN_ON(!gic->saved_espi_conf)) + goto out_free_spi_active; + + gic->saved_espi_target = kcalloc(GIC_ESPI_NR, + sizeof(*gic->saved_espi_target), + GFP_KERNEL); + if (WARN_ON(!gic->saved_espi_target)) + goto out_free_espi_conf; + + gic->saved_espi_enable = kcalloc(espi_size, + sizeof(*gic->saved_espi_enable), + GFP_KERNEL); + if (WARN_ON(!gic->saved_espi_enable)) + goto out_free_espi_target; + + gic->saved_espi_active = kcalloc(espi_size, + sizeof(*gic->saved_espi_active), + GFP_KERNEL); + if (WARN_ON(!gic->saved_espi_active)) + goto out_free_espi_enable; + + gic->saved_eppi_conf = kcalloc(DIV_ROUND_UP(gic->ppi_nr - 16, 16), + sizeof(*gic->saved_eppi_conf), + GFP_KERNEL); + if (WARN_ON(!gic->saved_eppi_conf)) + goto out_free_espi_active; + + gic->saved_eppi_enable = kcalloc(eppi_size, + sizeof(*gic->saved_eppi_enable), + GFP_KERNEL); + if (WARN_ON(!gic->saved_eppi_enable)) + goto out_free_eppi_conf; + + gic->saved_eppi_active = kcalloc(eppi_size, + sizeof(*gic->saved_eppi_active), + GFP_KERNEL); + if (WARN_ON(!gic->saved_eppi_active)) + goto out_free_eppi_enable; + cpu_pm_register_notifier(&gic_cpu_pm_notifier_block); return 0; + +out_free_eppi_enable: + kfree(gic->saved_eppi_enable); +out_free_eppi_conf: + kfree(gic->saved_eppi_conf); +out_free_espi_active: + kfree(gic->saved_espi_active); +out_free_espi_enable: + kfree(gic->saved_espi_enable); +out_free_espi_target: + kfree(gic->saved_espi_target); +out_free_espi_conf: + kfree(gic->saved_espi_conf); +out_free_spi_active: + kfree(gic->saved_spi_active); +out_free_spi_enable: + kfree(gic->saved_spi_enable); +out_free_spi_target: + kfree(gic->saved_spi_target); +out_free_spi_conf: + kfree(gic->saved_spi_conf); + return -ENOMEM; } #else diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 728691365464..40483530cadd 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -229,13 +229,17 @@ */ #define GICR_IGROUPR0 GICD_IGROUPR #define GICR_ISENABLER0 GICD_ISENABLER +#define GICR_ISENABLERnE GICD_ISENABLERnE #define GICR_ICENABLER0 GICD_ICENABLER #define GICR_ISPENDR0 GICD_ISPENDR #define GICR_ICPENDR0 GICD_ICPENDR #define GICR_ISACTIVER0 GICD_ISACTIVER +#define GICR_ISACTIVERnE GICD_ISACTIVERnE #define GICR_ICACTIVER0 GICD_ICACTIVER +#define GICR_ICACTIVERnE GICD_ICACTIVERnE #define GICR_IPRIORITYR0 GICD_IPRIORITYR #define GICR_ICFGR0 GICD_ICFGR +#define GICR_ICFGRnE GICD_ICFGRnE #define GICR_IGRPMODR0 GICD_IGRPMODR #define GICR_NSACR GICD_NSACR