linux-riscv.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation
@ 2023-03-08  6:46 Mason Huo
  2023-03-17  0:56 ` Mason Huo
  2023-03-29 16:44 ` Emil Renner Berthing
  0 siblings, 2 replies; 4+ messages in thread
From: Mason Huo @ 2023-03-08  6:46 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley
  Cc: linux-kernel, linux-riscv, Mason Huo, Ley Foon Tan, Sia Jee Heng

The priority and enable registers of plic will be reset
during hibernation power cycle in poweroff mode,
add the syscore callbacks to save/restore those registers.

Signed-off-by: Mason Huo <mason.huo@starfivetech.com>
Reviewed-by: Ley Foon Tan <leyfoon.tan@starfivetech.com>
Reviewed-by: Sia Jee Heng <jeeheng.sia@starfivetech.com>
Reported-by: Dan Carpenter <error27@gmail.com>
Link: https://lore.kernel.org/r/202302140709.CdkxgtPi-lkp@intel.com/
---
 drivers/irqchip/irq-sifive-plic.c | 93 ++++++++++++++++++++++++++++++-
 1 file changed, 91 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
index ff47bd0dec45..2800e7bb149a 100644
--- a/drivers/irqchip/irq-sifive-plic.c
+++ b/drivers/irqchip/irq-sifive-plic.c
@@ -17,6 +17,7 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
 #include <asm/smp.h>
 
 /*
@@ -67,6 +68,8 @@ struct plic_priv {
 	struct irq_domain *irqdomain;
 	void __iomem *regs;
 	unsigned long plic_quirks;
+	unsigned int nr_irqs;
+	unsigned long *prio_save;
 };
 
 struct plic_handler {
@@ -78,6 +81,7 @@ struct plic_handler {
 	 */
 	raw_spinlock_t		enable_lock;
 	void __iomem		*enable_base;
+	u32			*enable_save;
 	struct plic_priv	*priv;
 };
 static int plic_parent_irq __ro_after_init;
@@ -229,6 +233,71 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
 	return IRQ_SET_MASK_OK;
 }
 
+static int plic_irq_suspend(void)
+{
+	unsigned int i, cpu;
+	u32 __iomem *reg;
+	struct plic_priv *priv;
+
+	priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
+
+	for (i = 0; i < priv->nr_irqs; i++)
+		if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID))
+			__set_bit(i, priv->prio_save);
+		else
+			__clear_bit(i, priv->prio_save);
+
+	for_each_cpu(cpu, cpu_present_mask) {
+		struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
+
+		if (!handler->present)
+			continue;
+
+		raw_spin_lock(&handler->enable_lock);
+		for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
+			reg = handler->enable_base + i * sizeof(u32);
+			handler->enable_save[i] = readl(reg);
+		}
+		raw_spin_unlock(&handler->enable_lock);
+	}
+
+	return 0;
+}
+
+static void plic_irq_resume(void)
+{
+	unsigned int i, index, cpu;
+	u32 __iomem *reg;
+	struct plic_priv *priv;
+
+	priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
+
+	for (i = 0; i < priv->nr_irqs; i++) {
+		index = (i / BITS_PER_LONG);
+		writel((priv->prio_save[index] & BIT(i % BITS_PER_LONG)) ? 1 : 0,
+		       priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID);
+	}
+
+	for_each_cpu(cpu, cpu_present_mask) {
+		struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
+
+		if (!handler->present)
+			continue;
+
+		raw_spin_lock(&handler->enable_lock);
+		for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
+			reg = handler->enable_base + i * sizeof(u32);
+			writel(handler->enable_save[i], reg);
+		}
+		raw_spin_unlock(&handler->enable_lock);
+	}
+}
+
+static struct syscore_ops plic_irq_syscore_ops = {
+	.suspend	= plic_irq_suspend,
+	.resume		= plic_irq_resume,
+};
+
 static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
 			      irq_hw_number_t hwirq)
 {
@@ -345,6 +414,7 @@ static int __init __plic_init(struct device_node *node,
 	u32 nr_irqs;
 	struct plic_priv *priv;
 	struct plic_handler *handler;
+	unsigned int cpu;
 
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -363,15 +433,21 @@ static int __init __plic_init(struct device_node *node,
 	if (WARN_ON(!nr_irqs))
 		goto out_iounmap;
 
+	priv->nr_irqs = nr_irqs;
+
+	priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL);
+	if (!priv->prio_save)
+		goto out_free_priority_reg;
+
 	nr_contexts = of_irq_count(node);
 	if (WARN_ON(!nr_contexts))
-		goto out_iounmap;
+		goto out_free_priority_reg;
 
 	error = -ENOMEM;
 	priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
 			&plic_irqdomain_ops, priv);
 	if (WARN_ON(!priv->irqdomain))
-		goto out_iounmap;
+		goto out_free_priority_reg;
 
 	for (i = 0; i < nr_contexts; i++) {
 		struct of_phandle_args parent;
@@ -441,6 +517,11 @@ static int __init __plic_init(struct device_node *node,
 		handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
 			i * CONTEXT_ENABLE_SIZE;
 		handler->priv = priv;
+
+		handler->enable_save =  kcalloc(DIV_ROUND_UP(nr_irqs, 32),
+						sizeof(*handler->enable_save), GFP_KERNEL);
+		if (!handler->enable_save)
+			goto out_free_enable_reg;
 done:
 		for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
 			plic_toggle(handler, hwirq, 0);
@@ -461,11 +542,19 @@ static int __init __plic_init(struct device_node *node,
 				  plic_starting_cpu, plic_dying_cpu);
 		plic_cpuhp_setup_done = true;
 	}
+	register_syscore_ops(&plic_irq_syscore_ops);
 
 	pr_info("%pOFP: mapped %d interrupts with %d handlers for"
 		" %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
 	return 0;
 
+out_free_enable_reg:
+	for_each_cpu(cpu, cpu_present_mask) {
+		handler = per_cpu_ptr(&plic_handlers, cpu);
+		kfree(handler->enable_save);
+	}
+out_free_priority_reg:
+	kfree(priv->prio_save);
 out_iounmap:
 	iounmap(priv->regs);
 out_free_priv:
-- 
2.39.2


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation
  2023-03-08  6:46 [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation Mason Huo
@ 2023-03-17  0:56 ` Mason Huo
  2023-03-29 16:44 ` Emil Renner Berthing
  1 sibling, 0 replies; 4+ messages in thread
From: Mason Huo @ 2023-03-17  0:56 UTC (permalink / raw)
  To: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley
  Cc: linux-kernel, linux-riscv, Ley Foon Tan, Sia Jee Heng

Hi Marc,

Any feedback about the following v4 patch which is based on 6.3-rc1.

Thanks
Mason

On 2023/3/8 14:46, Mason Huo wrote:
> The priority and enable registers of plic will be reset
> during hibernation power cycle in poweroff mode,
> add the syscore callbacks to save/restore those registers.
> 
> Signed-off-by: Mason Huo <mason.huo@starfivetech.com>
> Reviewed-by: Ley Foon Tan <leyfoon.tan@starfivetech.com>
> Reviewed-by: Sia Jee Heng <jeeheng.sia@starfivetech.com>
> Reported-by: Dan Carpenter <error27@gmail.com>
> Link: https://lore.kernel.org/r/202302140709.CdkxgtPi-lkp@intel.com/
> ---
>  drivers/irqchip/irq-sifive-plic.c | 93 ++++++++++++++++++++++++++++++-
>  1 file changed, 91 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
> index ff47bd0dec45..2800e7bb149a 100644
> --- a/drivers/irqchip/irq-sifive-plic.c
> +++ b/drivers/irqchip/irq-sifive-plic.c
> @@ -17,6 +17,7 @@
>  #include <linux/of_irq.h>
>  #include <linux/platform_device.h>
>  #include <linux/spinlock.h>
> +#include <linux/syscore_ops.h>
>  #include <asm/smp.h>
>  
>  /*
> @@ -67,6 +68,8 @@ struct plic_priv {
>  	struct irq_domain *irqdomain;
>  	void __iomem *regs;
>  	unsigned long plic_quirks;
> +	unsigned int nr_irqs;
> +	unsigned long *prio_save;
>  };
>  
>  struct plic_handler {
> @@ -78,6 +81,7 @@ struct plic_handler {
>  	 */
>  	raw_spinlock_t		enable_lock;
>  	void __iomem		*enable_base;
> +	u32			*enable_save;
>  	struct plic_priv	*priv;
>  };
>  static int plic_parent_irq __ro_after_init;
> @@ -229,6 +233,71 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
>  	return IRQ_SET_MASK_OK;
>  }
>  
> +static int plic_irq_suspend(void)
> +{
> +	unsigned int i, cpu;
> +	u32 __iomem *reg;
> +	struct plic_priv *priv;
> +
> +	priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
> +
> +	for (i = 0; i < priv->nr_irqs; i++)
> +		if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID))
> +			__set_bit(i, priv->prio_save);
> +		else
> +			__clear_bit(i, priv->prio_save);
> +
> +	for_each_cpu(cpu, cpu_present_mask) {
> +		struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
> +
> +		if (!handler->present)
> +			continue;
> +
> +		raw_spin_lock(&handler->enable_lock);
> +		for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
> +			reg = handler->enable_base + i * sizeof(u32);
> +			handler->enable_save[i] = readl(reg);
> +		}
> +		raw_spin_unlock(&handler->enable_lock);
> +	}
> +
> +	return 0;
> +}
> +
> +static void plic_irq_resume(void)
> +{
> +	unsigned int i, index, cpu;
> +	u32 __iomem *reg;
> +	struct plic_priv *priv;
> +
> +	priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
> +
> +	for (i = 0; i < priv->nr_irqs; i++) {
> +		index = (i / BITS_PER_LONG);
> +		writel((priv->prio_save[index] & BIT(i % BITS_PER_LONG)) ? 1 : 0,
> +		       priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID);
> +	}
> +
> +	for_each_cpu(cpu, cpu_present_mask) {
> +		struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
> +
> +		if (!handler->present)
> +			continue;
> +
> +		raw_spin_lock(&handler->enable_lock);
> +		for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
> +			reg = handler->enable_base + i * sizeof(u32);
> +			writel(handler->enable_save[i], reg);
> +		}
> +		raw_spin_unlock(&handler->enable_lock);
> +	}
> +}
> +
> +static struct syscore_ops plic_irq_syscore_ops = {
> +	.suspend	= plic_irq_suspend,
> +	.resume		= plic_irq_resume,
> +};
> +
>  static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
>  			      irq_hw_number_t hwirq)
>  {
> @@ -345,6 +414,7 @@ static int __init __plic_init(struct device_node *node,
>  	u32 nr_irqs;
>  	struct plic_priv *priv;
>  	struct plic_handler *handler;
> +	unsigned int cpu;
>  
>  	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>  	if (!priv)
> @@ -363,15 +433,21 @@ static int __init __plic_init(struct device_node *node,
>  	if (WARN_ON(!nr_irqs))
>  		goto out_iounmap;
>  
> +	priv->nr_irqs = nr_irqs;
> +
> +	priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL);
> +	if (!priv->prio_save)
> +		goto out_free_priority_reg;
> +
>  	nr_contexts = of_irq_count(node);
>  	if (WARN_ON(!nr_contexts))
> -		goto out_iounmap;
> +		goto out_free_priority_reg;
>  
>  	error = -ENOMEM;
>  	priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
>  			&plic_irqdomain_ops, priv);
>  	if (WARN_ON(!priv->irqdomain))
> -		goto out_iounmap;
> +		goto out_free_priority_reg;
>  
>  	for (i = 0; i < nr_contexts; i++) {
>  		struct of_phandle_args parent;
> @@ -441,6 +517,11 @@ static int __init __plic_init(struct device_node *node,
>  		handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
>  			i * CONTEXT_ENABLE_SIZE;
>  		handler->priv = priv;
> +
> +		handler->enable_save =  kcalloc(DIV_ROUND_UP(nr_irqs, 32),
> +						sizeof(*handler->enable_save), GFP_KERNEL);
> +		if (!handler->enable_save)
> +			goto out_free_enable_reg;
>  done:
>  		for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
>  			plic_toggle(handler, hwirq, 0);
> @@ -461,11 +542,19 @@ static int __init __plic_init(struct device_node *node,
>  				  plic_starting_cpu, plic_dying_cpu);
>  		plic_cpuhp_setup_done = true;
>  	}
> +	register_syscore_ops(&plic_irq_syscore_ops);
>  
>  	pr_info("%pOFP: mapped %d interrupts with %d handlers for"
>  		" %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
>  	return 0;
>  
> +out_free_enable_reg:
> +	for_each_cpu(cpu, cpu_present_mask) {
> +		handler = per_cpu_ptr(&plic_handlers, cpu);
> +		kfree(handler->enable_save);
> +	}
> +out_free_priority_reg:
> +	kfree(priv->prio_save);
>  out_iounmap:
>  	iounmap(priv->regs);
>  out_free_priv:

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation
  2023-03-08  6:46 [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation Mason Huo
  2023-03-17  0:56 ` Mason Huo
@ 2023-03-29 16:44 ` Emil Renner Berthing
  2023-03-30 10:33   ` Mason Huo
  1 sibling, 1 reply; 4+ messages in thread
From: Emil Renner Berthing @ 2023-03-29 16:44 UTC (permalink / raw)
  To: Mason Huo
  Cc: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley,
	linux-kernel, linux-riscv, Ley Foon Tan, Sia Jee Heng

On Wed, 8 Mar 2023 at 07:49, Mason Huo <mason.huo@starfivetech.com> wrote:
>
> The priority and enable registers of plic will be reset
> during hibernation power cycle in poweroff mode,
> add the syscore callbacks to save/restore those registers.
>
> Signed-off-by: Mason Huo <mason.huo@starfivetech.com>
> Reviewed-by: Ley Foon Tan <leyfoon.tan@starfivetech.com>
> Reviewed-by: Sia Jee Heng <jeeheng.sia@starfivetech.com>
> Reported-by: Dan Carpenter <error27@gmail.com>
> Link: https://lore.kernel.org/r/202302140709.CdkxgtPi-lkp@intel.com/
> ---
>  drivers/irqchip/irq-sifive-plic.c | 93 ++++++++++++++++++++++++++++++-
>  1 file changed, 91 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
> index ff47bd0dec45..2800e7bb149a 100644
> --- a/drivers/irqchip/irq-sifive-plic.c
> +++ b/drivers/irqchip/irq-sifive-plic.c
> @@ -17,6 +17,7 @@
>  #include <linux/of_irq.h>
>  #include <linux/platform_device.h>
>  #include <linux/spinlock.h>
> +#include <linux/syscore_ops.h>
>  #include <asm/smp.h>
>
>  /*
> @@ -67,6 +68,8 @@ struct plic_priv {
>         struct irq_domain *irqdomain;
>         void __iomem *regs;
>         unsigned long plic_quirks;
> +       unsigned int nr_irqs;
> +       unsigned long *prio_save;
>  };
>
>  struct plic_handler {
> @@ -78,6 +81,7 @@ struct plic_handler {
>          */
>         raw_spinlock_t          enable_lock;
>         void __iomem            *enable_base;
> +       u32                     *enable_save;
>         struct plic_priv        *priv;
>  };
>  static int plic_parent_irq __ro_after_init;
> @@ -229,6 +233,71 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
>         return IRQ_SET_MASK_OK;
>  }
>
> +static int plic_irq_suspend(void)
> +{
> +       unsigned int i, cpu;
> +       u32 __iomem *reg;
> +       struct plic_priv *priv;
> +
> +       priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
> +
> +       for (i = 0; i < priv->nr_irqs; i++)
> +               if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID))
> +                       __set_bit(i, priv->prio_save);
> +               else
> +                       __clear_bit(i, priv->prio_save);
> +
> +       for_each_cpu(cpu, cpu_present_mask) {
> +               struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
> +
> +               if (!handler->present)
> +                       continue;
> +
> +               raw_spin_lock(&handler->enable_lock);
> +               for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
> +                       reg = handler->enable_base + i * sizeof(u32);
> +                       handler->enable_save[i] = readl(reg);
> +               }
> +               raw_spin_unlock(&handler->enable_lock);
> +       }
> +
> +       return 0;
> +}
> +
> +static void plic_irq_resume(void)
> +{
> +       unsigned int i, index, cpu;
> +       u32 __iomem *reg;
> +       struct plic_priv *priv;
> +
> +       priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
> +
> +       for (i = 0; i < priv->nr_irqs; i++) {
> +               index = (i / BITS_PER_LONG);
> +               writel((priv->prio_save[index] & BIT(i % BITS_PER_LONG)) ? 1 : 0,

This looks like BIT_WORD and test_bit (or at least BIT_MASK).

> +                      priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID);
> +       }
> +
> +       for_each_cpu(cpu, cpu_present_mask) {
> +               struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
> +
> +               if (!handler->present)
> +                       continue;
> +
> +               raw_spin_lock(&handler->enable_lock);
> +               for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
> +                       reg = handler->enable_base + i * sizeof(u32);
> +                       writel(handler->enable_save[i], reg);
> +               }
> +               raw_spin_unlock(&handler->enable_lock);
> +       }
> +}
> +
> +static struct syscore_ops plic_irq_syscore_ops = {
> +       .suspend        = plic_irq_suspend,
> +       .resume         = plic_irq_resume,
> +};
> +
>  static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
>                               irq_hw_number_t hwirq)
>  {
> @@ -345,6 +414,7 @@ static int __init __plic_init(struct device_node *node,
>         u32 nr_irqs;
>         struct plic_priv *priv;
>         struct plic_handler *handler;
> +       unsigned int cpu;
>
>         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>         if (!priv)
> @@ -363,15 +433,21 @@ static int __init __plic_init(struct device_node *node,
>         if (WARN_ON(!nr_irqs))
>                 goto out_iounmap;
>
> +       priv->nr_irqs = nr_irqs;
> +
> +       priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL);
> +       if (!priv->prio_save)
> +               goto out_free_priority_reg;
> +
>         nr_contexts = of_irq_count(node);
>         if (WARN_ON(!nr_contexts))
> -               goto out_iounmap;
> +               goto out_free_priority_reg;
>
>         error = -ENOMEM;
>         priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
>                         &plic_irqdomain_ops, priv);
>         if (WARN_ON(!priv->irqdomain))
> -               goto out_iounmap;
> +               goto out_free_priority_reg;
>
>         for (i = 0; i < nr_contexts; i++) {
>                 struct of_phandle_args parent;
> @@ -441,6 +517,11 @@ static int __init __plic_init(struct device_node *node,
>                 handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
>                         i * CONTEXT_ENABLE_SIZE;
>                 handler->priv = priv;
> +
> +               handler->enable_save =  kcalloc(DIV_ROUND_UP(nr_irqs, 32),
> +                                               sizeof(*handler->enable_save), GFP_KERNEL);
> +               if (!handler->enable_save)
> +                       goto out_free_enable_reg;
>  done:
>                 for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
>                         plic_toggle(handler, hwirq, 0);
> @@ -461,11 +542,19 @@ static int __init __plic_init(struct device_node *node,
>                                   plic_starting_cpu, plic_dying_cpu);
>                 plic_cpuhp_setup_done = true;
>         }
> +       register_syscore_ops(&plic_irq_syscore_ops);
>
>         pr_info("%pOFP: mapped %d interrupts with %d handlers for"
>                 " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
>         return 0;
>
> +out_free_enable_reg:
> +       for_each_cpu(cpu, cpu_present_mask) {
> +               handler = per_cpu_ptr(&plic_handlers, cpu);
> +               kfree(handler->enable_save);
> +       }
> +out_free_priority_reg:
> +       kfree(priv->prio_save);
>  out_iounmap:
>         iounmap(priv->regs);
>  out_free_priv:
> --
> 2.39.2
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation
  2023-03-29 16:44 ` Emil Renner Berthing
@ 2023-03-30 10:33   ` Mason Huo
  0 siblings, 0 replies; 4+ messages in thread
From: Mason Huo @ 2023-03-30 10:33 UTC (permalink / raw)
  To: Emil Renner Berthing
  Cc: Thomas Gleixner, Marc Zyngier, Palmer Dabbelt, Paul Walmsley,
	linux-kernel, linux-riscv, Ley Foon Tan, Sia Jee Heng



On 2023/3/30 0:44, Emil Renner Berthing wrote:
> On Wed, 8 Mar 2023 at 07:49, Mason Huo <mason.huo@starfivetech.com> wrote:
>>
>> The priority and enable registers of plic will be reset
>> during hibernation power cycle in poweroff mode,
>> add the syscore callbacks to save/restore those registers.
>>
>> Signed-off-by: Mason Huo <mason.huo@starfivetech.com>
>> Reviewed-by: Ley Foon Tan <leyfoon.tan@starfivetech.com>
>> Reviewed-by: Sia Jee Heng <jeeheng.sia@starfivetech.com>
>> Reported-by: Dan Carpenter <error27@gmail.com>
>> Link: https://lore.kernel.org/r/202302140709.CdkxgtPi-lkp@intel.com/
>> ---
>>  drivers/irqchip/irq-sifive-plic.c | 93 ++++++++++++++++++++++++++++++-
>>  1 file changed, 91 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
>> index ff47bd0dec45..2800e7bb149a 100644
>> --- a/drivers/irqchip/irq-sifive-plic.c
>> +++ b/drivers/irqchip/irq-sifive-plic.c
>> @@ -17,6 +17,7 @@
>>  #include <linux/of_irq.h>
>>  #include <linux/platform_device.h>
>>  #include <linux/spinlock.h>
>> +#include <linux/syscore_ops.h>
>>  #include <asm/smp.h>
>>
>>  /*
>> @@ -67,6 +68,8 @@ struct plic_priv {
>>         struct irq_domain *irqdomain;
>>         void __iomem *regs;
>>         unsigned long plic_quirks;
>> +       unsigned int nr_irqs;
>> +       unsigned long *prio_save;
>>  };
>>
>>  struct plic_handler {
>> @@ -78,6 +81,7 @@ struct plic_handler {
>>          */
>>         raw_spinlock_t          enable_lock;
>>         void __iomem            *enable_base;
>> +       u32                     *enable_save;
>>         struct plic_priv        *priv;
>>  };
>>  static int plic_parent_irq __ro_after_init;
>> @@ -229,6 +233,71 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
>>         return IRQ_SET_MASK_OK;
>>  }
>>
>> +static int plic_irq_suspend(void)
>> +{
>> +       unsigned int i, cpu;
>> +       u32 __iomem *reg;
>> +       struct plic_priv *priv;
>> +
>> +       priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
>> +
>> +       for (i = 0; i < priv->nr_irqs; i++)
>> +               if (readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID))
>> +                       __set_bit(i, priv->prio_save);
>> +               else
>> +                       __clear_bit(i, priv->prio_save);
>> +
>> +       for_each_cpu(cpu, cpu_present_mask) {
>> +               struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
>> +
>> +               if (!handler->present)
>> +                       continue;
>> +
>> +               raw_spin_lock(&handler->enable_lock);
>> +               for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
>> +                       reg = handler->enable_base + i * sizeof(u32);
>> +                       handler->enable_save[i] = readl(reg);
>> +               }
>> +               raw_spin_unlock(&handler->enable_lock);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static void plic_irq_resume(void)
>> +{
>> +       unsigned int i, index, cpu;
>> +       u32 __iomem *reg;
>> +       struct plic_priv *priv;
>> +
>> +       priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
>> +
>> +       for (i = 0; i < priv->nr_irqs; i++) {
>> +               index = (i / BITS_PER_LONG);
>> +               writel((priv->prio_save[index] & BIT(i % BITS_PER_LONG)) ? 1 : 0,
> 
> This looks like BIT_WORD and test_bit (or at least BIT_MASK).
> 
Hi Emil,
Thanks for your review, will replace it. 

>> +                      priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID);
>> +       }
>> +
>> +       for_each_cpu(cpu, cpu_present_mask) {
>> +               struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
>> +
>> +               if (!handler->present)
>> +                       continue;
>> +
>> +               raw_spin_lock(&handler->enable_lock);
>> +               for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) {
>> +                       reg = handler->enable_base + i * sizeof(u32);
>> +                       writel(handler->enable_save[i], reg);
>> +               }
>> +               raw_spin_unlock(&handler->enable_lock);
>> +       }
>> +}
>> +
>> +static struct syscore_ops plic_irq_syscore_ops = {
>> +       .suspend        = plic_irq_suspend,
>> +       .resume         = plic_irq_resume,
>> +};
>> +
>>  static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
>>                               irq_hw_number_t hwirq)
>>  {
>> @@ -345,6 +414,7 @@ static int __init __plic_init(struct device_node *node,
>>         u32 nr_irqs;
>>         struct plic_priv *priv;
>>         struct plic_handler *handler;
>> +       unsigned int cpu;
>>
>>         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
>>         if (!priv)
>> @@ -363,15 +433,21 @@ static int __init __plic_init(struct device_node *node,
>>         if (WARN_ON(!nr_irqs))
>>                 goto out_iounmap;
>>
>> +       priv->nr_irqs = nr_irqs;
>> +
>> +       priv->prio_save = bitmap_alloc(nr_irqs, GFP_KERNEL);
>> +       if (!priv->prio_save)
>> +               goto out_free_priority_reg;
>> +
>>         nr_contexts = of_irq_count(node);
>>         if (WARN_ON(!nr_contexts))
>> -               goto out_iounmap;
>> +               goto out_free_priority_reg;
>>
>>         error = -ENOMEM;
>>         priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
>>                         &plic_irqdomain_ops, priv);
>>         if (WARN_ON(!priv->irqdomain))
>> -               goto out_iounmap;
>> +               goto out_free_priority_reg;
>>
>>         for (i = 0; i < nr_contexts; i++) {
>>                 struct of_phandle_args parent;
>> @@ -441,6 +517,11 @@ static int __init __plic_init(struct device_node *node,
>>                 handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE +
>>                         i * CONTEXT_ENABLE_SIZE;
>>                 handler->priv = priv;
>> +
>> +               handler->enable_save =  kcalloc(DIV_ROUND_UP(nr_irqs, 32),
>> +                                               sizeof(*handler->enable_save), GFP_KERNEL);
>> +               if (!handler->enable_save)
>> +                       goto out_free_enable_reg;
>>  done:
>>                 for (hwirq = 1; hwirq <= nr_irqs; hwirq++) {
>>                         plic_toggle(handler, hwirq, 0);
>> @@ -461,11 +542,19 @@ static int __init __plic_init(struct device_node *node,
>>                                   plic_starting_cpu, plic_dying_cpu);
>>                 plic_cpuhp_setup_done = true;
>>         }
>> +       register_syscore_ops(&plic_irq_syscore_ops);
>>
>>         pr_info("%pOFP: mapped %d interrupts with %d handlers for"
>>                 " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts);
>>         return 0;
>>
>> +out_free_enable_reg:
>> +       for_each_cpu(cpu, cpu_present_mask) {
>> +               handler = per_cpu_ptr(&plic_handlers, cpu);
>> +               kfree(handler->enable_save);
>> +       }
>> +out_free_priority_reg:
>> +       kfree(priv->prio_save);
>>  out_iounmap:
>>         iounmap(priv->regs);
>>  out_free_priv:
>> --
>> 2.39.2
>>
>>
>> _______________________________________________
>> linux-riscv mailing list
>> linux-riscv@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-riscv

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2023-03-30 10:34 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-08  6:46 [PATCH v4] irqchip/irq-sifive-plic: Add syscore callbacks for hibernation Mason Huo
2023-03-17  0:56 ` Mason Huo
2023-03-29 16:44 ` Emil Renner Berthing
2023-03-30 10:33   ` Mason Huo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).