Re: [PATCH v4] openrisc: irq: use irqchip framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




CC devicetree for the bindings

On Mon, May 26, 2014 at 10:31 PM, Stefan Kristiansson
<stefan.kristiansson@xxxxxxxxxxxxx> wrote:
> In addition to consolidating the or1k-pic with other interrupt
> controllers, this makes OpenRISC less tied to its on-cpu
> interrupt controller.
>
> All or1k-pic specific parts are moved out of irq.c and into
> drivers/irqchip/irq-or1k-pic.c
>
> In that transition, the funtionality have been divided into
> three chip variants.
> One that handles level triggered interrupts, one that handles edge
> triggered interrupts and one that handles the interrupt
> controller that is present in the or1200 OpenRISC cpu
> implementation.
>
> Signed-off-by: Stefan Kristiansson <stefan.kristiansson@xxxxxxxxxxxxx>
> ---
> Changes in v2:
>  - Move or1k-pic related code into irq-or1k-pic
>  - Add documentation for device tree bindings
>
> Changes in v3:
>  - Split level-, edge-triggered and or1200 implementation into seperate
>    chip variants.
>
> Changes in v4:
>  - Fix typos in documentation
> ---
>  .../interrupt-controller/opencores,or1k-pic.txt    |  23 +++
>  arch/openrisc/Kconfig                              |   1 +
>  arch/openrisc/include/asm/irq.h                    |   3 +
>  arch/openrisc/kernel/irq.c                         | 146 ++---------------
>  drivers/irqchip/Kconfig                            |   4 +
>  drivers/irqchip/Makefile                           |   1 +
>  drivers/irqchip/irq-or1k-pic.c                     | 182 +++++++++++++++++++++
>  7 files changed, 227 insertions(+), 133 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt
>  create mode 100644 drivers/irqchip/irq-or1k-pic.c
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt b/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt
> new file mode 100644
> index 0000000..55c04fa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt
> @@ -0,0 +1,23 @@
> +OpenRISC 1000 Programmable Interrupt Controller
> +
> +Required properties:
> +
> +- compatible : should be "opencores,or1k-pic-level" for variants with
> +  level triggered interrupt lines, "opencores,or1k-pic-edge" for variants with
> +  edge triggered interrupt lines or "opencores,or1200-pic" for machines
> +  with the non-spec compliant or1200 type implementation.
> +
> +  "opencores,or1k-pic" is also provided as an alias to "opencores,or1200-pic",
> +  but this is only for backwards compatibility.
> +
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : Specifies the number of cells needed to encode an
> +  interrupt source. The value shall be 1.
> +
> +Example:
> +
> +intc: interrupt-controller {
> +       compatible = "opencores,or1k-pic-level";
> +       interrupt-controller;
> +       #interrupt-cells = <1>;
> +};
> diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
> index e71d712..88e8336 100644
> --- a/arch/openrisc/Kconfig
> +++ b/arch/openrisc/Kconfig
> @@ -22,6 +22,7 @@ config OPENRISC
>         select GENERIC_STRNLEN_USER
>         select MODULES_USE_ELF_RELA
>         select HAVE_DEBUG_STACKOVERFLOW
> +       select OR1K_PIC
>
>  config MMU
>         def_bool y
> diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h
> index eb612b1..b84634c 100644
> --- a/arch/openrisc/include/asm/irq.h
> +++ b/arch/openrisc/include/asm/irq.h
> @@ -24,4 +24,7 @@
>
>  #define NO_IRQ         (-1)
>
> +void handle_IRQ(unsigned int, struct pt_regs *);
> +extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
> +
>  #endif /* __ASM_OPENRISC_IRQ_H__ */
> diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c
> index 8ec77bc..967eb14 100644
> --- a/arch/openrisc/kernel/irq.c
> +++ b/arch/openrisc/kernel/irq.c
> @@ -16,11 +16,10 @@
>
>  #include <linux/interrupt.h>
>  #include <linux/init.h>
> -#include <linux/of.h>
>  #include <linux/ftrace.h>
>  #include <linux/irq.h>
> +#include <linux/irqchip.h>
>  #include <linux/export.h>
> -#include <linux/irqdomain.h>
>  #include <linux/irqflags.h>
>
>  /* read interrupt enabled status */
> @@ -37,150 +36,31 @@ void arch_local_irq_restore(unsigned long flags)
>  }
>  EXPORT_SYMBOL(arch_local_irq_restore);
>
> -
> -/* OR1K PIC implementation */
> -
> -/* We're a couple of cycles faster than the generic implementations with
> - * these 'fast' versions.
> - */
> -
> -static void or1k_pic_mask(struct irq_data *data)
> -{
> -       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
> -}
> -
> -static void or1k_pic_unmask(struct irq_data *data)
> -{
> -       mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
> -}
> -
> -static void or1k_pic_ack(struct irq_data *data)
> -{
> -       /* EDGE-triggered interrupts need to be ack'ed in order to clear
> -        * the latch.
> -        * LEVEL-triggered interrupts do not need to be ack'ed; however,
> -        * ack'ing the interrupt has no ill-effect and is quicker than
> -        * trying to figure out what type it is...
> -        */
> -
> -       /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the
> -        * interrupt, but the OR1200 does this backwards and requires a 0
> -        * to be written...
> -        */
> -
> -#ifdef CONFIG_OR1K_1200
> -       /* There are two oddities with the OR1200 PIC implementation:
> -        * i)  LEVEL-triggered interrupts are latched and need to be cleared
> -        * ii) the interrupt latch is cleared by writing a 0 to the bit,
> -        *     as opposed to a 1 as mandated by the spec
> -        */
> -
> -       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
> -#else
> -       WARN(1, "Interrupt handling possibly broken\n");
> -       mtspr(SPR_PICSR, (1UL << data->hwirq));
> -#endif
> -}
> -
> -static void or1k_pic_mask_ack(struct irq_data *data)
> -{
> -       /* Comments for pic_ack apply here, too */
> -
> -#ifdef CONFIG_OR1K_1200
> -       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
> -       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
> -#else
> -       WARN(1, "Interrupt handling possibly broken\n");
> -       mtspr(SPR_PICMR, (1UL << data->hwirq));
> -       mtspr(SPR_PICSR, (1UL << data->hwirq));
> -#endif
> -}
> -
> -#if 0
> -static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type)
> -{
> -       /* There's nothing to do in the PIC configuration when changing
> -        * flow type.  Level and edge-triggered interrupts are both
> -        * supported, but it's PIC-implementation specific which type
> -        * is handled. */
> -
> -       return irq_setup_alt_chip(data, flow_type);
> -}
> -#endif
> -
> -static struct irq_chip or1k_dev = {
> -       .name = "or1k-PIC",
> -       .irq_unmask = or1k_pic_unmask,
> -       .irq_mask = or1k_pic_mask,
> -       .irq_ack = or1k_pic_ack,
> -       .irq_mask_ack = or1k_pic_mask_ack,
> -};
> -
> -static struct irq_domain *root_domain;
> -
> -static inline int pic_get_irq(int first)
> -{
> -       int hwirq;
> -
> -       hwirq = ffs(mfspr(SPR_PICSR) >> first);
> -       if (!hwirq)
> -               return NO_IRQ;
> -       else
> -               hwirq = hwirq + first -1;
> -
> -       return irq_find_mapping(root_domain, hwirq);
> -}
> -
> -
> -static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
> +void __init init_IRQ(void)
>  {
> -       irq_set_chip_and_handler_name(irq, &or1k_dev,
> -                                     handle_level_irq, "level");
> -       irq_set_status_flags(irq, IRQ_LEVEL | IRQ_NOPROBE);
> -
> -       return 0;
> +       irqchip_init();
>  }
>
> -static const struct irq_domain_ops or1k_irq_domain_ops = {
> -       .xlate = irq_domain_xlate_onecell,
> -       .map = or1k_map,
> -};
> -
> -/*
> - * This sets up the IRQ domain for the PIC built in to the OpenRISC
> - * 1000 CPU.  This is the "root" domain as these are the interrupts
> - * that directly trigger an exception in the CPU.
> - */
> -static void __init or1k_irq_init(void)
> -{
> -       struct device_node *intc = NULL;
> -
> -       /* The interrupt controller device node is mandatory */
> -       intc = of_find_compatible_node(NULL, NULL, "opencores,or1k-pic");
> -       BUG_ON(!intc);
> -
> -       /* Disable all interrupts until explicitly requested */
> -       mtspr(SPR_PICMR, (0UL));
> -
> -       root_domain = irq_domain_add_linear(intc, 32,
> -                                           &or1k_irq_domain_ops, NULL);
> -}
> +static void (*handle_arch_irq)(struct pt_regs *);
>
> -void __init init_IRQ(void)
> +void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
>  {
> -       or1k_irq_init();
> +       handle_arch_irq = handle_irq;
>  }
>
> -void __irq_entry do_IRQ(struct pt_regs *regs)
> +void handle_IRQ(unsigned int irq, struct pt_regs *regs)
>  {
> -       int irq = -1;
>         struct pt_regs *old_regs = set_irq_regs(regs);
>
>         irq_enter();
>
> -       while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
> -               generic_handle_irq(irq);
> +       generic_handle_irq(irq);
>
>         irq_exit();
>         set_irq_regs(old_regs);
>  }
> +
> +void __irq_entry do_IRQ(struct pt_regs *regs)
> +{
> +       handle_arch_irq(regs);
> +}
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index d770f74..f06e4c8 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -47,6 +47,10 @@ config CLPS711X_IRQCHIP
>         select SPARSE_IRQ
>         default y
>
> +config OR1K_PIC
> +       bool
> +       select IRQ_DOMAIN
> +
>  config ORION_IRQCHIP
>         bool
>         select IRQ_DOMAIN
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index f180f8d..4377695 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_METAG)                   += irq-metag-ext.o
>  obj-$(CONFIG_METAG_PERFCOUNTER_IRQS)   += irq-metag.o
>  obj-$(CONFIG_ARCH_MOXART)              += irq-moxart.o
>  obj-$(CONFIG_CLPS711X_IRQCHIP)         += irq-clps711x.o
> +obj-$(CONFIG_OR1K_PIC)                 += irq-or1k-pic.o
>  obj-$(CONFIG_ORION_IRQCHIP)            += irq-orion.o
>  obj-$(CONFIG_ARCH_SUNXI)               += irq-sun4i.o
>  obj-$(CONFIG_ARCH_SUNXI)               += irq-sunxi-nmi.o
> diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c
> new file mode 100644
> index 0000000..17ff033
> --- /dev/null
> +++ b/drivers/irqchip/irq-or1k-pic.c
> @@ -0,0 +1,182 @@
> +/*
> + * Copyright (C) 2010-2011 Jonas Bonn <jonas@xxxxxxxxxxxx>
> + * Copyright (C) 2014 Stefan Kristansson <stefan.kristiansson@xxxxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/irq.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_address.h>
> +
> +#include "irqchip.h"
> +
> +/* OR1K PIC implementation */
> +
> +struct or1k_pic_dev {
> +       struct irq_chip chip;
> +       irq_flow_handler_t handle;
> +       unsigned long flags;
> +};
> +
> +/*
> + * We're a couple of cycles faster than the generic implementations with
> + * these 'fast' versions.
> + */
> +
> +static void or1k_pic_mask(struct irq_data *data)
> +{
> +       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
> +}
> +
> +static void or1k_pic_unmask(struct irq_data *data)
> +{
> +       mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
> +}
> +
> +static void or1k_pic_ack(struct irq_data *data)
> +{
> +       mtspr(SPR_PICSR, (1UL << data->hwirq));
> +}
> +
> +static void or1k_pic_mask_ack(struct irq_data *data)
> +{
> +       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
> +       mtspr(SPR_PICSR, (1UL << data->hwirq));
> +}
> +
> +/*
> + * There are two oddities with the OR1200 PIC implementation:
> + * i)  LEVEL-triggered interrupts are latched and need to be cleared
> + * ii) the interrupt latch is cleared by writing a 0 to the bit,
> + *     as opposed to a 1 as mandated by the spec
> + */
> +static void or1k_pic_or1200_ack(struct irq_data *data)
> +{
> +       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
> +}
> +
> +static void or1k_pic_or1200_mask_ack(struct irq_data *data)
> +{
> +       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
> +       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
> +}
> +
> +static struct or1k_pic_dev or1k_pic_level = {
> +       .chip = {
> +               .name = "or1k-PIC-level",
> +               .irq_unmask = or1k_pic_unmask,
> +               .irq_mask = or1k_pic_mask,
> +               .irq_mask_ack = or1k_pic_mask,
> +       },
> +       .handle = handle_level_irq,
> +       .flags = IRQ_LEVEL | IRQ_NOPROBE,
> +};
> +
> +static struct or1k_pic_dev or1k_pic_edge = {
> +       .chip = {
> +               .name = "or1k-PIC-edge",
> +               .irq_unmask = or1k_pic_unmask,
> +               .irq_mask = or1k_pic_mask,
> +               .irq_ack = or1k_pic_ack,
> +               .irq_mask_ack = or1k_pic_mask_ack,
> +       },
> +       .handle = handle_edge_irq,
> +       .flags = IRQ_LEVEL | IRQ_NOPROBE,
> +};
> +
> +static struct or1k_pic_dev or1k_pic_or1200 = {
> +       .chip = {
> +               .name = "or1200-PIC",
> +               .irq_unmask = or1k_pic_unmask,
> +               .irq_mask = or1k_pic_mask,
> +               .irq_ack = or1k_pic_or1200_ack,
> +               .irq_mask_ack = or1k_pic_or1200_mask_ack,
> +       },
> +       .handle = handle_level_irq,
> +       .flags = IRQ_LEVEL | IRQ_NOPROBE,
> +};
> +
> +static struct irq_domain *root_domain;
> +
> +static inline int pic_get_irq(int first)
> +{
> +       int hwirq;
> +
> +       hwirq = ffs(mfspr(SPR_PICSR) >> first);
> +       if (!hwirq)
> +               return NO_IRQ;
> +       else
> +               hwirq = hwirq + first - 1;
> +
> +       return irq_find_mapping(root_domain, hwirq);
> +}
> +
> +static void or1k_pic_handle_irq(struct pt_regs *regs)
> +{
> +       int irq = -1;
> +
> +       while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
> +               handle_IRQ(irq, regs);
> +}
> +
> +static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
> +{
> +       struct or1k_pic_dev *pic = d->host_data;
> +
> +       irq_set_chip_and_handler(irq, &pic->chip, pic->handle);
> +       irq_set_status_flags(irq, pic->flags);
> +
> +       return 0;
> +}
> +
> +static const struct irq_domain_ops or1k_irq_domain_ops = {
> +       .xlate = irq_domain_xlate_onecell,
> +       .map = or1k_map,
> +};
> +
> +/*
> + * This sets up the IRQ domain for the PIC built in to the OpenRISC
> + * 1000 CPU.  This is the "root" domain as these are the interrupts
> + * that directly trigger an exception in the CPU.
> + */
> +static int __init or1k_pic_init(struct device_node *node,
> +                                struct or1k_pic_dev *pic)
> +{
> +       /* Disable all interrupts until explicitly requested */
> +       mtspr(SPR_PICMR, (0UL));
> +
> +       root_domain = irq_domain_add_linear(node, 32, &or1k_irq_domain_ops,
> +                                           pic);
> +
> +       set_handle_irq(or1k_pic_handle_irq);
> +
> +       return 0;
> +}
> +
> +static int __init or1k_pic_or1200_init(struct device_node *node,
> +                                      struct device_node *parent)
> +{
> +       return or1k_pic_init(node, &or1k_pic_or1200);
> +}
> +IRQCHIP_DECLARE(or1k_pic_or1200, "opencores,or1200-pic", or1k_pic_or1200_init);
> +IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_pic_or1200_init);
> +
> +static int __init or1k_pic_level_init(struct device_node *node,
> +                                     struct device_node *parent)
> +{
> +       return or1k_pic_init(node, &or1k_pic_level);
> +}
> +IRQCHIP_DECLARE(or1k_pic_level, "opencores,or1k-pic-level",
> +               or1k_pic_level_init);
> +
> +static int __init or1k_pic_edge_init(struct device_node *node,
> +                                    struct device_node *parent)
> +{
> +       return or1k_pic_init(node, &or1k_pic_edge);
> +}
> +IRQCHIP_DECLARE(or1k_pic_edge, "opencores,or1k-pic-edge", or1k_pic_edge_init);
> --
> 1.8.3.2
>



-- 
Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

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
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux