/*
  * Routines to acknowledge, disable and enable interrupts
  */
-static void gic_mask_irq(struct irq_data *d)
+static void gic_poke_irq(struct irq_data *d, u32 offset)
+{
+       u32 mask = 1 << (gic_irq(d) % 32);
+       writel_relaxed(mask, gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4);
+}
+
+static int gic_peek_irq(struct irq_data *d, u32 offset)
 {
        u32 mask = 1 << (gic_irq(d) % 32);
+       return !!(readl_relaxed(gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4) & mask);
+}
+
+static void gic_mask_irq(struct irq_data *d)
+{
        unsigned long flags;
 
        raw_spin_lock_irqsave(&irq_controller_lock, flags);
-       writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
+       gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR);
        if (gic_arch_extn.irq_mask)
                gic_arch_extn.irq_mask(d);
        raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 
 static void gic_unmask_irq(struct irq_data *d)
 {
-       u32 mask = 1 << (gic_irq(d) % 32);
        unsigned long flags;
 
        raw_spin_lock_irqsave(&irq_controller_lock, flags);
        if (gic_arch_extn.irq_unmask)
                gic_arch_extn.irq_unmask(d);
-       writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
+       gic_poke_irq(d, GIC_DIST_ENABLE_SET);
        raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 
        writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
 }
 
+static int gic_irq_set_irqchip_state(struct irq_data *d,
+                                    enum irqchip_irq_state which, bool val)
+{
+       u32 reg;
+
+       switch (which) {
+       case IRQCHIP_STATE_PENDING:
+               reg = val ? GIC_DIST_PENDING_SET : GIC_DIST_PENDING_CLEAR;
+               break;
+
+       case IRQCHIP_STATE_ACTIVE:
+               reg = val ? GIC_DIST_ACTIVE_SET : GIC_DIST_ACTIVE_CLEAR;
+               break;
+
+       case IRQCHIP_STATE_MASKED:
+               reg = val ? GIC_DIST_ENABLE_CLEAR : GIC_DIST_ENABLE_SET;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       gic_poke_irq(d, reg);
+       return 0;
+}
+
+static int gic_irq_get_irqchip_state(struct irq_data *d,
+                                     enum irqchip_irq_state which, bool *val)
+{
+       switch (which) {
+       case IRQCHIP_STATE_PENDING:
+               *val = gic_peek_irq(d, GIC_DIST_PENDING_SET);
+               break;
+
+       case IRQCHIP_STATE_ACTIVE:
+               *val = gic_peek_irq(d, GIC_DIST_ACTIVE_SET);
+               break;
+
+       case IRQCHIP_STATE_MASKED:
+               *val = !gic_peek_irq(d, GIC_DIST_ENABLE_SET);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int gic_set_type(struct irq_data *d, unsigned int type)
 {
        void __iomem *base = gic_dist_base(d);
        .irq_set_affinity       = gic_set_affinity,
 #endif
        .irq_set_wake           = gic_set_wake,
+       .irq_get_irqchip_state  = gic_irq_get_irqchip_state,
+       .irq_set_irqchip_state  = gic_irq_set_irqchip_state,
 };
 
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)