lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <ZsO9ZmNXa3uvzctr@ghost>
Date: Mon, 19 Aug 2024 14:47:18 -0700
From: Charlie Jenkins <charlie@...osinc.com>
To: Anup Patel <apatel@...tanamicro.com>
Cc: Emil Renner Berthing <emil.renner.berthing@...onical.com>,
	Thomas Gleixner <tglx@...utronix.de>,
	Anup Patel <anup@...infault.org>,
	Paul Walmsley <paul.walmsley@...ive.com>,
	linux-kernel@...r.kernel.org,
	Samuel Holland <samuel.holland@...ive.com>,
	Palmer Dabbelt <palmer@...belt.com>,
	Atish Patra <atishp@...shpatra.org>,
	linux-riscv@...ts.infradead.org,
	Andrew Jones <ajones@...tanamicro.com>
Subject: Re: [PATCH v2] irqchip/sifive-plic: Probe plic driver early for
 Allwinner D1 platform

On Mon, Aug 19, 2024 at 08:27:33PM +0530, Anup Patel wrote:
> On Mon, Aug 19, 2024 at 12:27 PM Emil Renner Berthing
> <emil.renner.berthing@...onical.com> wrote:
> >
> > Anup Patel wrote:
> > > The latest Linux RISC-V no longer boots on the Allwinner D1 platform
> > > because the sun4i_timer driver fails to get an interrupt from PLIC.
> > >
> > > The real fix requires enabling the SBI time extension in the platform
> > > firmware (OpenSBI) and convert sun4i_timer into platform driver.
> > > Unfortunately, the real fix involves changing multiple places and
> > > can't be achieved in a short duration.
> > >
> > > As a work-around, retrofit plic probing such that plic is probed
> > > early only for the Allwinner D1 platform and probed as a regular
> > > platform driver for rest of the RISC-V platforms. In the process,
> > > partially revert some of the previous patches because PLIC device
> > > pointer is not available in all probing paths.
> > >
> > > More detailed discussion can found here:
> > > https://lore.kernel.org/lkml/20240814145642.344485-1-emil.renner.berthing@canonical.com/
> > >
> > > Fixes: e306a894bd51 ("irqchip/sifive-plic: Chain to parent IRQ after handlers are ready")
> > > Fixes: 8ec99b033147 ("irqchip/sifive-plic: Convert PLIC driver into a platform driver")
> > > Suggested-by: Thomas Gleixner <tglx@...utronix.de>
> > > Reviewed-by: Samuel Holland <samuel.holland@...ive.com>
> > > Tested-by: Samuel Holland <samuel.holland@...ive.com>
> > > Signed-off-by: Anup Patel <apatel@...tanamicro.com>
> > > ---
> > > Changes since v1:
> > >  - Set suppress_bind_attrs for PLIC platform driver
> > > ---
> > >  drivers/irqchip/irq-sifive-plic.c | 128 +++++++++++++++++++-----------
> > >  1 file changed, 80 insertions(+), 48 deletions(-)
> > >
> > > diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c
> > > index 9e22f7e378f5..33395c5a9b5b 100644
> > > --- a/drivers/irqchip/irq-sifive-plic.c
> > > +++ b/drivers/irqchip/irq-sifive-plic.c
> > > @@ -3,6 +3,7 @@
> > >   * Copyright (C) 2017 SiFive
> > >   * Copyright (C) 2018 Christoph Hellwig
> > >   */
> > > +#define pr_fmt(fmt) "riscv-plic: " fmt
> > >  #include <linux/cpu.h>
> > >  #include <linux/interrupt.h>
> > >  #include <linux/io.h>
> > > @@ -63,7 +64,7 @@
> > >  #define PLIC_QUIRK_EDGE_INTERRUPT    0
> > >
> > >  struct plic_priv {
> > > -     struct device *dev;
> > > +     struct fwnode_handle *fwnode;
> > >       struct cpumask lmask;
> > >       struct irq_domain *irqdomain;
> > >       void __iomem *regs;
> > > @@ -378,8 +379,8 @@ static void plic_handle_irq(struct irq_desc *desc)
> > >               int err = generic_handle_domain_irq(handler->priv->irqdomain,
> > >                                                   hwirq);
> > >               if (unlikely(err)) {
> > > -                     dev_warn_ratelimited(handler->priv->dev,
> > > -                                          "can't find mapping for hwirq %lu\n", hwirq);
> > > +                     pr_warn_ratelimited("%pfwP: can't find mapping for hwirq %lu\n",
> > > +                                         handler->priv->fwnode, hwirq);
> > >               }
> > >       }
> > >
> > > @@ -408,15 +409,14 @@ static int plic_starting_cpu(unsigned int cpu)
> > >               enable_percpu_irq(plic_parent_irq,
> > >                                 irq_get_trigger_type(plic_parent_irq));
> > >       else
> > > -             dev_warn(handler->priv->dev, "cpu%d: parent irq not available\n", cpu);
> > > +             pr_warn("%pfwP: cpu%d: parent irq not available\n",
> > > +                     handler->priv->fwnode, cpu);
> > >       plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD);
> > >
> > >       return 0;
> > >  }
> > >
> > > -static const struct of_device_id plic_match[] = {
> > > -     { .compatible = "sifive,plic-1.0.0" },
> > > -     { .compatible = "riscv,plic0" },
> > > +static const struct of_device_id plic_quirks_match[] = {
> > >       { .compatible = "andestech,nceplic100",
> > >         .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
> > >       { .compatible = "thead,c900-plic",
> > > @@ -424,38 +424,36 @@ static const struct of_device_id plic_match[] = {
> > >       {}
> > >  };
> > >
> > > -static int plic_parse_nr_irqs_and_contexts(struct platform_device *pdev,
> > > +static int plic_parse_nr_irqs_and_contexts(struct fwnode_handle *fwnode,
> > >                                          u32 *nr_irqs, u32 *nr_contexts)
> > >  {
> > > -     struct device *dev = &pdev->dev;
> > >       int rc;
> > >
> > >       /*
> > >        * Currently, only OF fwnode is supported so extend this
> > >        * function for ACPI support.
> > >        */
> > > -     if (!is_of_node(dev->fwnode))
> > > +     if (!is_of_node(fwnode))
> > >               return -EINVAL;
> > >
> > > -     rc = of_property_read_u32(to_of_node(dev->fwnode), "riscv,ndev", nr_irqs);
> > > +     rc = of_property_read_u32(to_of_node(fwnode), "riscv,ndev", nr_irqs);
> > >       if (rc) {
> > > -             dev_err(dev, "riscv,ndev property not available\n");
> > > +             pr_err("%pfwP: riscv,ndev property not available\n", fwnode);
> > >               return rc;
> > >       }
> > >
> > > -     *nr_contexts = of_irq_count(to_of_node(dev->fwnode));
> > > +     *nr_contexts = of_irq_count(to_of_node(fwnode));
> > >       if (WARN_ON(!(*nr_contexts))) {
> > > -             dev_err(dev, "no PLIC context available\n");
> > > +             pr_err("%pfwP: no PLIC context available\n", fwnode);
> > >               return -EINVAL;
> > >       }
> > >
> > >       return 0;
> > >  }
> > >
> > > -static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
> > > +static int plic_parse_context_parent(struct fwnode_handle *fwnode, u32 context,
> > >                                    u32 *parent_hwirq, int *parent_cpu)
> > >  {
> > > -     struct device *dev = &pdev->dev;
> > >       struct of_phandle_args parent;
> > >       unsigned long hartid;
> > >       int rc;
> > > @@ -464,10 +462,10 @@ static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
> > >        * Currently, only OF fwnode is supported so extend this
> > >        * function for ACPI support.
> > >        */
> > > -     if (!is_of_node(dev->fwnode))
> > > +     if (!is_of_node(fwnode))
> > >               return -EINVAL;
> > >
> > > -     rc = of_irq_parse_one(to_of_node(dev->fwnode), context, &parent);
> > > +     rc = of_irq_parse_one(to_of_node(fwnode), context, &parent);
> > >       if (rc)
> > >               return rc;
> > >
> > > @@ -480,48 +478,55 @@ static int plic_parse_context_parent(struct platform_device *pdev, u32 context,
> > >       return 0;
> > >  }
> > >
> > > -static int plic_probe(struct platform_device *pdev)
> > > +static int plic_probe(struct fwnode_handle *fwnode)
> > >  {
> > >       int error = 0, nr_contexts, nr_handlers = 0, cpu, i;
> > > -     struct device *dev = &pdev->dev;
> > >       unsigned long plic_quirks = 0;
> > >       struct plic_handler *handler;
> > >       u32 nr_irqs, parent_hwirq;
> > >       struct plic_priv *priv;
> > >       irq_hw_number_t hwirq;
> > > +     void __iomem *regs;
> > >
> > > -     if (is_of_node(dev->fwnode)) {
> > > +     if (is_of_node(fwnode)) {
> > >               const struct of_device_id *id;
> > >
> > > -             id = of_match_node(plic_match, to_of_node(dev->fwnode));
> > > +             id = of_match_node(plic_quirks_match, to_of_node(fwnode));
> > >               if (id)
> > >                       plic_quirks = (unsigned long)id->data;
> > > +
> > > +             regs = of_iomap(to_of_node(fwnode), 0);
> > > +             if (!regs)
> > > +                     return -ENOMEM;
> > > +     } else {
> > > +             return -ENODEV;
> >
> > This driver never worked with ACPI anyways?
> >
> > >       }
> > >
> > > -     error = plic_parse_nr_irqs_and_contexts(pdev, &nr_irqs, &nr_contexts);
> > > +     error = plic_parse_nr_irqs_and_contexts(fwnode, &nr_irqs, &nr_contexts);
> > >       if (error)
> > > -             return error;
> > > +             goto fail_free_regs;
> > >
> > > -     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > > -     if (!priv)
> > > -             return -ENOMEM;
> > > +     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> > > +     if (!priv) {
> > > +             error = -ENOMEM;
> > > +             goto fail_free_regs;
> > > +     }
> > >
> > > -     priv->dev = dev;
> > > +     priv->fwnode = fwnode;
> > >       priv->plic_quirks = plic_quirks;
> > >       priv->nr_irqs = nr_irqs;
> > > +     priv->regs = regs;
> > >
> > > -     priv->regs = devm_platform_ioremap_resource(pdev, 0);
> > > -     if (WARN_ON(!priv->regs))
> > > -             return -EIO;
> > > -
> > > -     priv->prio_save = devm_bitmap_zalloc(dev, nr_irqs, GFP_KERNEL);
> > > -     if (!priv->prio_save)
> > > -             return -ENOMEM;
> > > +     priv->prio_save = bitmap_zalloc(nr_irqs, GFP_KERNEL);
> > > +     if (!priv->prio_save) {
> > > +             error = -ENOMEM;
> > > +             goto fail_free_priv;
> > > +     }
> > >
> > >       for (i = 0; i < nr_contexts; i++) {
> > > -             error = plic_parse_context_parent(pdev, i, &parent_hwirq, &cpu);
> > > +             error = plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu);
> > >               if (error) {
> > > -                     dev_warn(dev, "hwirq for context%d not found\n", i);
> > > +                     pr_warn("%pfwP: hwirq for context%d not found\n", fwnode, i);
> > >                       continue;
> > >               }
> > >
> > > @@ -543,7 +548,7 @@ static int plic_probe(struct platform_device *pdev)
> > >               }
> > >
> > >               if (cpu < 0) {
> > > -                     dev_warn(dev, "Invalid cpuid for context %d\n", i);
> > > +                     pr_warn("%pfwP: Invalid cpuid for context %d\n", fwnode, i);
> > >                       continue;
> > >               }
> > >
> > > @@ -554,7 +559,7 @@ static int plic_probe(struct platform_device *pdev)
> > >                */
> > >               handler = per_cpu_ptr(&plic_handlers, cpu);
> > >               if (handler->present) {
> > > -                     dev_warn(dev, "handler already present for context %d.\n", i);
> > > +                     pr_warn("%pfwP: handler already present for context %d.\n", fwnode, i);
> > >                       plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD);
> > >                       goto done;
> > >               }
> > > @@ -568,8 +573,8 @@ static int plic_probe(struct platform_device *pdev)
> > >                       i * CONTEXT_ENABLE_SIZE;
> > >               handler->priv = priv;
> > >
> > > -             handler->enable_save = devm_kcalloc(dev, DIV_ROUND_UP(nr_irqs, 32),
> > > -                                                 sizeof(*handler->enable_save), GFP_KERNEL);
> > > +             handler->enable_save = kcalloc(DIV_ROUND_UP(nr_irqs, 32),
> > > +                                            sizeof(*handler->enable_save), GFP_KERNEL);
> > >               if (!handler->enable_save)
> > >                       goto fail_cleanup_contexts;
> > >  done:
> > > @@ -581,7 +586,7 @@ static int plic_probe(struct platform_device *pdev)
> > >               nr_handlers++;
> > >       }
> > >
> > > -     priv->irqdomain = irq_domain_add_linear(to_of_node(dev->fwnode), nr_irqs + 1,
> > > +     priv->irqdomain = irq_domain_add_linear(to_of_node(fwnode), nr_irqs + 1,
> > >                                               &plic_irqdomain_ops, priv);
> > >       if (WARN_ON(!priv->irqdomain))
> > >               goto fail_cleanup_contexts;
> > > @@ -619,13 +624,13 @@ static int plic_probe(struct platform_device *pdev)
> > >               }
> > >       }
> > >
> > > -     dev_info(dev, "mapped %d interrupts with %d handlers for %d contexts.\n",
> > > -              nr_irqs, nr_handlers, nr_contexts);
> > > +     pr_info("%pfwP: mapped %d interrupts with %d handlers for %d contexts.\n",
> > > +             fwnode, nr_irqs, nr_handlers, nr_contexts);
> > >       return 0;
> > >
> > >  fail_cleanup_contexts:
> > >       for (i = 0; i < nr_contexts; i++) {
> > > -             if (plic_parse_context_parent(pdev, i, &parent_hwirq, &cpu))
> > > +             if (plic_parse_context_parent(fwnode, i, &parent_hwirq, &cpu))
> > >                       continue;
> > >               if (parent_hwirq != RV_IRQ_EXT || cpu < 0)
> > >                       continue;
> > > @@ -634,17 +639,44 @@ static int plic_probe(struct platform_device *pdev)
> > >               handler->present = false;
> > >               handler->hart_base = NULL;
> > >               handler->enable_base = NULL;
> > > +             kfree(handler->enable_save);
> > >               handler->enable_save = NULL;
> > >               handler->priv = NULL;
> > >       }
> > > -     return -ENOMEM;
> > > +     bitmap_free(priv->prio_save);
> > > +fail_free_priv:
> > > +     kfree(priv);
> > > +fail_free_regs:
> > > +     iounmap(regs);
> > > +     return error;
> > > +}
> > > +
> > > +static int plic_platform_probe(struct platform_device *pdev)
> > > +{
> > > +     return plic_probe(pdev->dev.fwnode);
> > >  }
> > >
> > > +static const struct of_device_id plic_platform_match[] = {
> > > +     { .compatible = "sifive,plic-1.0.0" },
> > > +     { .compatible = "riscv,plic0" },
> > > +     { .compatible = "andestech,nceplic100" },
> > > +     {}
> > > +};
> > > +
> > >  static struct platform_driver plic_driver = {
> > >       .driver = {
> > >               .name           = "riscv-plic",
> > > -             .of_match_table = plic_match,
> > > +             .of_match_table = plic_platform_match,
> > > +             .suppress_bind_attrs = true,
> > >       },
> > > -     .probe = plic_probe,
> > > +     .probe = plic_platform_probe,
> > >  };
> > >  builtin_platform_driver(plic_driver);
> > > +
> > > +static int __init plic_early_probe(struct device_node *node,
> > > +                                struct device_node *parent)
> > > +{
> > > +     return plic_probe(&node->fwnode);
> > > +}
> > > +
> > > +IRQCHIP_DECLARE(riscv, "thead,c900-plic", plic_early_probe);
> >
> > If this is only needed on the Allwinner D1 maybe this should only match the
> > more specific "allwinner,sun20i-d1-plic"?
> >
> > In any case this works by itself, but not with Samuel's patch[1] applied, so
> > Tested-by: Emil Renner Berthing <emil.renner.berthing@...onical.com>
> >
> > [1]: https://lore.kernel.org/r/20240312192519.1602493-1-samuel.holland@sifive.com
> 
> Thanks for testing.
> 
> Can you confirm that using "allwinner,sun20i-d1-plic" for early
> probe works on the Allwinner D1 board ? If yes, the I will quickly
> send a v3.

I can confirm that this patch works as-is, and with
"allwinner,sun20i-d1-plic" for early probe on the Allwiner D1 board.
Thank you for this fix Anup!

Reviewed-by: Charlie Jenkins <charlie@...osinc.com>
Tested-by: Charlie Jenkins <charlie@...osinc.com>

> 
> Regards,
> Anup
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@...ts.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ