]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
drivers: irqchip: agic_route API implementation
authorAjay Nandakumar <anandakumarm@nvidia.com>
Mon, 26 May 2014 11:59:32 +0000 (17:29 +0530)
committerNitin Kumbhar <nkumbhar@nvidia.com>
Wed, 4 Jun 2014 05:55:27 +0000 (22:55 -0700)
agic_route API has been causing crashes when changing the target CPU
of the irq. Earlier byte write was used. Moving it to word write.

Bug 200000611

Change-Id: I3204dd74bc04e4c4b80e273ee41789a494161b40
Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com>
Signed-off-by: Nitin Kumbhar <nkumbhar@nvidia.com>
Reviewed-on: http://git-master/r/414988
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit

drivers/irqchip/irq-gic.c

index 5eca9598320d573f225fe17452deaea4abcf9386..4c911bf2ba23d0e1cdc7e7e621058375db69a0ce 100644 (file)
@@ -179,29 +179,41 @@ EXPORT_SYMBOL_GPL(tegra_agic_irq_is_active);
 int tegra_agic_route_interrupt(int irq, enum tegra_agic_cpu cpu)
 {
        void __iomem *dist_base = gic_data_dist_base(tegra_agic);
-       u32 irq_target = GIC_DIST_TARGET + irq;
+       u32 irq_target = GIC_DIST_TARGET + (irq & ~3);
+       u32 shift = (irq % 4) * 8;
        u32 irq_clear_enable = GIC_DIST_ENABLE_CLEAR + (irq / 32) * 4;
        u32 val32;
-       u8 val8;
+       u32 irq_aff;
        u8 routing_cpu = 1 << (u32)cpu;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&irq_controller_lock, flags);
-       val8 = readb_relaxed(dist_base + irq_target);
-       if (val8 & routing_cpu) {
-               raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+       irq_aff = readl_relaxed(dist_base + irq_target);
+       if (irq_aff & (routing_cpu << shift)) {
+               raw_spin_unlock_irqrestore(&irq_controller_lock,
+                                                       flags);
+               pr_info("routing agic irq %d to same cpu\n", irq);
                return -EINVAL;
        }
 
-       val32 =  readl(dist_base + irq_clear_enable);
+       val32 = readl(dist_base + irq_clear_enable);
 
        /* Check whether the irq is enabled */
        if (val32 & (1 << (irq % 32))) {
-               raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+               raw_spin_unlock_irqrestore(&irq_controller_lock,
+                                                       flags);
+               pr_info("agic irq %d is enabled, cannot be routed\n",
+                                                               irq);
                return -EPERM;
        }
-       writeb_relaxed(routing_cpu, dist_base + irq_target);
+
+       /* clear the byte with the word field */
+       irq_aff = irq_aff & ~(0xFF << shift);
+       writel_relaxed(irq_aff, dist_base + irq_target);
+       irq_aff = irq_aff | (routing_cpu << shift);
+       writel_relaxed(irq_aff, dist_base + irq_target);
        raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(tegra_agic_route_interrupt);