Re: [PATCH V3 2/2] irqchip/irq-csky-mpintc: Add triger type and priority

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

 



Hi Marc,
ping ... Any problem ?

Thx
 Guo Ren

<guoren@xxxxxxxxxx> 于2019年5月13日周一 下午5:55写道:
>
> From: Guo Ren <ren_guo@xxxxxxxxx>
>
> Support 4 triger types:
>  - IRQ_TYPE_LEVEL_HIGH
>  - IRQ_TYPE_LEVEL_LOW
>  - IRQ_TYPE_EDGE_RISING
>  - IRQ_TYPE_EDGE_FALLING
>
> Support 0-255 priority setting for each irq.
>
> All of above could be set in DeviceTree file and it still compatible
> with the old DeviceTree format.
>
> Changes for V3:
>  - Use IRQ_TYPE_LEVEL_HIGH as default instead of IRQ_TYPE_NONE
>  - Remove unnecessary loop in csky_mpintc_handler
>
> Changes for V2:
>  - Fixup this_cpu_read() preempted problem.
>  - Optimize the coding style.
>
> Signed-off-by: Guo Ren <ren_guo@xxxxxxxxx>
> Cc: Marc Zyngier <marc.zyngier@xxxxxxx>
> ---
>  drivers/irqchip/irq-csky-mpintc.c | 113 +++++++++++++++++++++++++++++++++++---
>  1 file changed, 106 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/irqchip/irq-csky-mpintc.c b/drivers/irqchip/irq-csky-mpintc.c
> index c67c961..5bc0868 100644
> --- a/drivers/irqchip/irq-csky-mpintc.c
> +++ b/drivers/irqchip/irq-csky-mpintc.c
> @@ -17,6 +17,7 @@
>  #include <asm/reg_ops.h>
>
>  static struct irq_domain *root_domain;
> +
>  static void __iomem *INTCG_base;
>  static void __iomem *INTCL_base;
>
> @@ -29,11 +30,13 @@ static void __iomem *INTCL_base;
>
>  #define INTCG_ICTLR    0x0
>  #define INTCG_CICFGR   0x100
> +#define INTCG_CIPRTR   0x200
>  #define INTCG_CIDSTR   0x1000
>
>  #define INTCL_PICTLR   0x0
> +#define INTCL_CFGR     0x14
> +#define INTCL_PRTR     0x20
>  #define INTCL_SIGR     0x60
> -#define INTCL_HPPIR    0x68
>  #define INTCL_RDYIR    0x6c
>  #define INTCL_SENR     0xa0
>  #define INTCL_CENR     0xa4
> @@ -41,21 +44,66 @@ static void __iomem *INTCL_base;
>
>  static DEFINE_PER_CPU(void __iomem *, intcl_reg);
>
> +static unsigned long *__trigger;
> +static unsigned long *__priority;
> +
> +#define IRQ_OFFSET(irq) ((irq < COMM_IRQ_BASE) ? irq : (irq - COMM_IRQ_BASE))
> +
> +#define TRIG_BYTE_OFFSET(i)    ((((i) * 2) / 32) * 4)
> +#define TRIG_BIT_OFFSET(i)      (((i) * 2) % 32)
> +
> +#define PRI_BYTE_OFFSET(i)     ((((i) * 8) / 32) * 4)
> +#define PRI_BIT_OFFSET(i)       (((i) * 8) % 32)
> +
> +#define TRIG_VAL(trigger, irq) (trigger << TRIG_BIT_OFFSET(IRQ_OFFSET(irq)))
> +#define TRIG_VAL_MSK(irq)          (~(3 << TRIG_BIT_OFFSET(IRQ_OFFSET(irq))))
> +#define PRI_VAL(priority, irq) (priority << PRI_BIT_OFFSET(IRQ_OFFSET(irq)))
> +#define PRI_VAL_MSK(irq)         (~(0xff << PRI_BIT_OFFSET(IRQ_OFFSET(irq))))
> +
> +#define TRIG_BASE(irq) \
> +       (TRIG_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \
> +       (this_cpu_read(intcl_reg) + INTCL_CFGR) : (INTCG_base + INTCG_CICFGR)))
> +
> +#define PRI_BASE(irq) \
> +       (PRI_BYTE_OFFSET(IRQ_OFFSET(irq)) + ((irq < COMM_IRQ_BASE) ? \
> +       (this_cpu_read(intcl_reg) + INTCL_PRTR) : (INTCG_base + INTCG_CIPRTR)))
> +
> +static DEFINE_SPINLOCK(setup_lock);
> +static void setup_trigger_priority(unsigned long irq, unsigned long trigger,
> +                                  unsigned long priority)
> +{
> +       unsigned int tmp;
> +
> +       spin_lock(&setup_lock);
> +
> +       /* setup trigger */
> +       tmp = readl_relaxed(TRIG_BASE(irq)) & TRIG_VAL_MSK(irq);
> +
> +       writel_relaxed(tmp | TRIG_VAL(trigger, irq), TRIG_BASE(irq));
> +
> +       /* setup priority */
> +       tmp = readl_relaxed(PRI_BASE(irq)) & PRI_VAL_MSK(irq);
> +
> +       writel_relaxed(tmp | PRI_VAL(priority, irq), PRI_BASE(irq));
> +
> +       spin_unlock(&setup_lock);
> +}
> +
>  static void csky_mpintc_handler(struct pt_regs *regs)
>  {
>         void __iomem *reg_base = this_cpu_read(intcl_reg);
>
> -       do {
> -               handle_domain_irq(root_domain,
> -                                 readl_relaxed(reg_base + INTCL_RDYIR),
> -                                 regs);
> -       } while (readl_relaxed(reg_base + INTCL_HPPIR) & BIT(31));
> +       handle_domain_irq(root_domain,
> +               readl_relaxed(reg_base + INTCL_RDYIR), regs);
>  }
>
>  static void csky_mpintc_enable(struct irq_data *d)
>  {
>         void __iomem *reg_base = this_cpu_read(intcl_reg);
>
> +       setup_trigger_priority(d->hwirq, __trigger[d->hwirq],
> +                                __priority[d->hwirq]);
> +
>         writel_relaxed(d->hwirq, reg_base + INTCL_SENR);
>  }
>
> @@ -73,6 +121,28 @@ static void csky_mpintc_eoi(struct irq_data *d)
>         writel_relaxed(d->hwirq, reg_base + INTCL_CACR);
>  }
>
> +static int csky_mpintc_set_type(struct irq_data *d, unsigned int type)
> +{
> +       switch (type & IRQ_TYPE_SENSE_MASK) {
> +       case IRQ_TYPE_LEVEL_HIGH:
> +               __trigger[d->hwirq] = 0;
> +               break;
> +       case IRQ_TYPE_LEVEL_LOW:
> +               __trigger[d->hwirq] = 1;
> +               break;
> +       case IRQ_TYPE_EDGE_RISING:
> +               __trigger[d->hwirq] = 2;
> +               break;
> +       case IRQ_TYPE_EDGE_FALLING:
> +               __trigger[d->hwirq] = 3;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
>  #ifdef CONFIG_SMP
>  static int csky_irq_set_affinity(struct irq_data *d,
>                                  const struct cpumask *mask_val,
> @@ -105,6 +175,7 @@ static struct irq_chip csky_irq_chip = {
>         .irq_eoi        = csky_mpintc_eoi,
>         .irq_enable     = csky_mpintc_enable,
>         .irq_disable    = csky_mpintc_disable,
> +       .irq_set_type   = csky_mpintc_set_type,
>  #ifdef CONFIG_SMP
>         .irq_set_affinity = csky_irq_set_affinity,
>  #endif
> @@ -125,9 +196,29 @@ static int csky_irqdomain_map(struct irq_domain *d, unsigned int irq,
>         return 0;
>  }
>
> +static int csky_irq_domain_xlate_cells(struct irq_domain *d,
> +               struct device_node *ctrlr, const u32 *intspec,
> +               unsigned int intsize, unsigned long *out_hwirq,
> +               unsigned int *out_type)
> +{
> +       if (WARN_ON(intsize < 1))
> +               return -EINVAL;
> +
> +       *out_hwirq = intspec[0];
> +       if (intsize > 1)
> +               *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
> +       else
> +               *out_type = IRQ_TYPE_LEVEL_HIGH;
> +
> +       if (intsize > 2)
> +               __priority[*out_hwirq] = intspec[2];
> +
> +       return 0;
> +}
> +
>  static const struct irq_domain_ops csky_irqdomain_ops = {
>         .map    = csky_irqdomain_map,
> -       .xlate  = irq_domain_xlate_onecell,
> +       .xlate  = csky_irq_domain_xlate_cells,
>  };
>
>  #ifdef CONFIG_SMP
> @@ -161,6 +252,14 @@ csky_mpintc_init(struct device_node *node, struct device_node *parent)
>         if (ret < 0)
>                 nr_irq = INTC_IRQS;
>
> +       __priority = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL);
> +       if (__priority == NULL)
> +               return -ENXIO;
> +
> +       __trigger  = kcalloc(nr_irq, sizeof(unsigned long), GFP_KERNEL);
> +       if (__trigger == NULL)
> +               return -ENXIO;
> +
>         if (INTCG_base == NULL) {
>                 INTCG_base = ioremap(mfcr("cr<31, 14>"),
>                                      INTCL_SIZE*nr_cpu_ids + INTCG_SIZE);
> --
> 2.7.4
>




[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