Re: [RESEND RFC PATCH 05/12] drivers/irqchip: Add SH7751 and boards specific irqchip.

Geert Uytterhoeven <[email protected]>
Newsgroups gmane.linux.ports.sh.devel
Message-ID <CAMuHMdV9-vJxt_PKnM715QL+9E7uaK4SVx-YtcTppHeufsmSFg@mail.gmail.com>
Hi Sato-san,

Thanks for your patch!

On Thu, Aug 31, 2023 at 4:37 PM Yoshinori Sato
<[email protected]> wrote:
> - irq-renesas-sh7751: Renesas SH7751 internal INTC.
> - irq-renesas-r2d: Renesas RTS7751R2D external interrupt encoder.
> - irq-iodata-julian: IO DATA Device LANDISK external interrupt encoder.

Again, please split.

> Signed-off-by: Yoshinori Sato <[email protected]>

> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -660,6 +660,10 @@ config APPLE_AIC
>         help
>           Support for the Apple Interrupt Controller found on Apple Silicon SoCs,
>           such as the M1.

Please add a blank line here.

> +config RENESAS_SH_INTC
> +       def_bool y if SH_DEVICE_TREE
> +       select IRQ_DOMAIN
> +       select IRQ_DOMAIN_HIERARCHY
>
>  config MCHP_EIC
>         bool "Microchip External Interrupt Controller"
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index ffd945fe71aa..a3859bdd0442 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -120,3 +120,4 @@ obj-$(CONFIG_IRQ_IDT3243X)          += irq-idt3243x.o
>  obj-$(CONFIG_APPLE_AIC)                        += irq-apple-aic.o
>  obj-$(CONFIG_MCHP_EIC)                 += irq-mchp-eic.o
>  obj-$(CONFIG_SUNPLUS_SP7021_INTC)      += irq-sp7021-intc.o
> +obj-$(CONFIG_RENESAS_SH_INTC)          += irq-renesas-sh7751.o irq-iodata-julian.o irq-renesas-r2d.o

I think it makes sense to split this in 3 different config symbols.

> diff --git a/drivers/irqchip/irq-iodata-julian.c b/drivers/irqchip/irq-iodata-julian.c
> new file mode 100644
> index 000000000000..95e502904a68
> --- /dev/null
> +++ b/drivers/irqchip/irq-iodata-julian.c
> @@ -0,0 +1,163 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * IO-DATA DEVICE LANDISK / USL-5P (a.k.a Julian) interrupt encoder
> + *
> + * Copyright (C) 2023 Yoshinori Sato
> + */
> +
> +#include <linux/init.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_address.h>

Do you need this?

> +#include <linux/of_irq.h>

Do you need this?

> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#define NUM_IRQ 16
> +
> +struct julian_intc_priv {
> +       struct device *dev;
> +       void __iomem *base;
> +       struct irq_domain *irq_domain;
> +};
> +
> +static struct julian_intc_priv *irq_data_to_priv(struct irq_data *data)

static inline

> +{
> +       return data->domain->host_data;
> +}

> +static __init int julian_intc_map(struct irq_domain *h, unsigned int virq,

I don't think this can be __init...

> +                              irq_hw_number_t hw_irq_num)
> +{
> +       irq_set_chip_and_handler(virq, &julian_intc_chip, handle_level_irq);
> +       irq_get_irq_data(virq)->chip_data = h->host_data;
> +       irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOPROBE);
> +       return 0;
> +}

> +static int julian_intc_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct device_node *np = dev->of_node;
> +       struct julian_intc_priv *priv;
> +       struct irq_domain *d;
> +       int ret = 0;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->dev = dev;
> +
> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(priv->base))
> +               return PTR_ERR(priv->base);
> +
> +       d = irq_domain_add_tree(np, &julian_intc_domain_ops, priv);
> +       if (d == NULL) {
> +               dev_err(dev, "cannot initialize irq domain\n");
> +               kfree(priv);
> +               ret = -ENOMEM;

"return -ENOMEM;", so you can bail out early, remove the else below,
and reduce indentation below.

> +       } else {
> +               priv->irq_domain = d;
> +               irq_domain_update_bus_token(d, DOMAIN_BUS_WIRED);
> +       }
> +       return ret;
> +}

> +static int julian_intc_remove(struct platform_device *pdev)
> +{
> +       struct julian_intc_priv *priv = platform_get_drvdata(pdev);

This won't work, as platform_set_drvdata() is never called.

> +
> +       irq_domain_remove(priv->irq_domain);
> +       return 0;
> +}
> +
> +static const struct of_device_id julian_intc_dt_ids[] = {
> +       { .compatible = "iodata,julian-intc" },
> +       {},

Please no comma after a sentinel.

> +};
> +MODULE_DEVICE_TABLE(of, julian_intc_dt_ids);

> --- /dev/null
> +++ b/drivers/irqchip/irq-renesas-r2d.c
> @@ -0,0 +1,175 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Renesas RTS7751R2D interrupt encoder
> + *
> + * Copyright (C) 2023 Yoshinori Sato
> + */
> +
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/of_irq.h>

Do you need this?

> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +
> +#define NUM_IRQ 15
> +
> +struct r2d_intc_priv {
> +       struct device *dev;
> +       void __iomem *base;
> +       struct irq_domain *irq_domain;
> +};
> +
> +static const int imask[] = {

unsigned int

> +       1 << 11,        /* PCI INTD */
> +       1 << 9,         /* CF IDE */
> +       1 << 8,         /* CF CD */
> +       1 << 12,        /* PCI INTC */
> +       1 << 10,        /* SM501 */
> +       1 << 6,         /* AX88796 / KEY */
> +       1 << 5,         /* RTC ALARM */
> +       1 << 4,         /* RTC T */
> +       1 << 7,         /* SDCARD */
> +       1 << 14,        /* PCI INTA */
> +       1 << 13,        /* PCI INTB */
> +       1 << 0,         /* EXT */
> +       1 << 15,        /* TP */

BIT(...)

> +};
> +
> +static struct r2d_intc_priv *irq_data_to_priv(struct irq_data *data)

static inline

> +{
> +       return data->domain->host_data;
> +}

> +static __init int r2d_intc_map(struct irq_domain *h, unsigned int virq,
> +                              irq_hw_number_t hw_irq_num)

I don't think this can be __init.

> +{
> +       irq_set_chip_and_handler(virq, &r2d_intc_chip, handle_level_irq);
> +       irq_get_irq_data(virq)->chip_data = h->host_data;
> +       irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOPROBE);
> +       return 0;
> +}

> +static const struct irq_domain_ops r2d_intc_domain_ops = {
> +//     .alloc = r2d_intc_alloc,

Remove this line?

> +       .map = r2d_intc_map,
> +       .translate = r2d_intc_translate,
> +};
> +
> +static int r2d_intc_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct device_node *np = dev->of_node;
> +       struct r2d_intc_priv *priv;
> +       struct irq_domain *d;
> +       int ret = 0;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->dev = dev;
> +
> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(priv->base))
> +               return PTR_ERR(priv->base);
> +
> +       d = irq_domain_add_tree(np, &r2d_intc_domain_ops, priv);
> +       if (d == NULL) {
> +               dev_err(dev, "cannot initialize irq domain\n");
> +               kfree(priv);
> +               ret = -ENOMEM;

"return -ENOMEM;", so you can bail out early, remove the else below,
and reduce indentation below.

> +       } else {
> +               priv->irq_domain = d;
> +               irq_domain_update_bus_token(d, DOMAIN_BUS_WIRED);
> +       }
> +       return ret;
> +}
> +
> +static int r2d_intc_remove(struct platform_device *pdev)
> +{
> +       struct r2d_intc_priv *priv = platform_get_drvdata(pdev);

This won't work, as platform_set_drvdata() is never called.

> +
> +       irq_domain_remove(priv->irq_domain);
> +       return 0;
> +}
> +
> +static const struct of_device_id r2d_intc_dt_ids[] = {
> +       { .compatible = "renesas,rts7751r2d-intc" },
> +       {},

Please no comma after a sentinel.

> +};
> +MODULE_DEVICE_TABLE(of, r2d_intc_dt_ids);

> --- /dev/null
> +++ b/drivers/irqchip/irq-renesas-sh7751.c
> @@ -0,0 +1,186 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Renesas SH7751 interrupt controller driver
> + *
> + * Copyright 2023 Yoshinori Sato <[email protected]>
> + */
> +
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/of_address.h>

Do you need this?

> +#include <linux/of_irq.h>

Do you need this?

> +static void update_ipr(struct sh7751_intc_regs *reg, int irq, int on)
> +{
> +       unsigned int addr;
> +       int pos;

unsigned int

> +       uint16_t pri;
> +
> +       if (irq < 64) {
> +               if (ipr_table[irq] != 0xff) {
> +                       addr = (ipr_table[irq] & 0xf0) >> 2;
> +                       pos = (ipr_table[irq] & 0x0f) * 4;
> +                       pri = ~(0x000f << pos);
> +                       pri &= __raw_readw(reg->ipr + addr);
> +                       if (on)
> +                               pri |= 1 << pos;
> +                       __raw_writew(pri, reg->ipr + addr);
> +               }
> +       } else {
> +               if (pri_table[irq - 64] < 32) {

else if

> +                       pos = pri_table[irq - 64];
> +                       pri = ~(0x000f << pos);
> +                       pri &= __raw_readw(reg->intpri00);
> +                       if (on)
> +                               pri |= 1 << pos;
> +                       __raw_writew(pri, reg->intpri00);
> +               }
> +       }
> +}
> +
> +static void sh7751_disable_irq(struct irq_data *data)
> +{
> +       unsigned int irq = data->irq;
> +       struct sh7751_intc_regs *reg = data->chip_data;
> +       uint16_t icr = __raw_readw(reg->icr);
> +
> +       if (irq < 16 && (icr & ICR_IRLM) == 0) {
> +               clear_bit(irq, imask_mask);
> +               if (interrupt_priority < IMASK_PRIORITY - irq)
> +                       interrupt_priority = IMASK_PRIORITY - irq;
> +               set_interrupt_registers(interrupt_priority);
> +       } else
> +               update_ipr(reg, irq, 0);

Missing curly braces for else case.

> +}
> +
> +static void sh7751_enable_irq(struct irq_data *data)
> +{
> +       unsigned int irq = data->irq;
> +       struct sh7751_intc_regs *reg = data->chip_data;
> +       uint16_t icr = __raw_readw(reg->icr);
> +
> +       if (irq < 16 && (icr & ICR_IRLM) == 0) {
> +               set_bit(irq, imask_mask);
> +               interrupt_priority = IMASK_PRIORITY -
> +                 find_first_bit(imask_mask, IMASK_PRIORITY);

wrong indentation

> +               set_interrupt_registers(interrupt_priority);
> +       } else
> +               update_ipr(reg, irq, 1);

Missing curly braces for else case.

> +}

> +static int __init sh7751_intc_of_init(struct device_node *intc,
> +                                     struct device_node *parent)
> +{
> +       unsigned short icr;

u16

> +       struct irq_domain *domain;
> +       void *intc_baseaddr;
> +       void *intc_baseaddr2;
> +
> +       intc_baseaddr = of_iomap(intc, 0);
> +       intc_baseaddr2 = of_iomap(intc, 1);
> +       if (!intc_baseaddr) {
> +               pr_err("Invalid INTC address\n");
> +               return -EINVAL;
> +       }
> +
> +       sh7751_regs.icr = intc_baseaddr;
> +       sh7751_regs.ipr = intc_baseaddr + 4;
> +       sh7751_regs.intpri00 = intc_baseaddr2;
> +       sh7751_regs.intreq00 = intc_baseaddr2 + 0x20;
> +       sh7751_regs.intmsk00 = intc_baseaddr2 + 0x40;
> +       sh7751_regs.intmskclr00 = intc_baseaddr2 + 0x60;
> +
> +       if (of_property_read_bool(intc, "sh7751,irlm")) {
> +               icr = __raw_readw(sh7751_regs.icr);
> +               icr |= 0x80;    // IRLM = 1

#define ICR_IRLM BIT(7)

> +               __raw_writew(icr, sh7751_regs.icr);
> +       }
> +
> +       domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, &sh7751_regs);
> +       if (!domain) {
> +               pr_err("Unable to allocate domain handle\n");
> +               return -ENOMEM;
> +       }
> +       irq_set_default_host(domain);
> +       return 0;
> +}
> +
> +IRQCHIP_DECLARE(sh_7751_intc,
> +               "renesas,sh7751-intc", sh7751_intc_of_init);

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.