OSDN Git Service

Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
[uclinux-h8/linux.git] / drivers / irqchip / irq-gic.c
index f1efb53..7b315e3 100644 (file)
@@ -153,13 +153,24 @@ static inline unsigned int gic_irq(struct irq_data *d)
 /*
  * 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);
@@ -167,13 +178,12 @@ static void gic_mask_irq(struct irq_data *d)
 
 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);
 }
 
@@ -188,6 +198,55 @@ static void gic_eoi_irq(struct irq_data *d)
        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);
@@ -331,6 +390,8 @@ static struct irq_chip gic_chip = {
        .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)
@@ -355,7 +416,7 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
                        break;
        }
 
-       if (!mask)
+       if (!mask && num_possible_cpus() > 1)
                pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
 
        return mask;
@@ -804,15 +865,12 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data,
                                    handle_fasteoi_irq, NULL, NULL);
                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
-
-               gic_routable_irq_domain_ops->map(d, irq, hw);
        }
        return 0;
 }
 
 static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
 {
-       gic_routable_irq_domain_ops->unmap(d, irq);
 }
 
 static int gic_irq_domain_xlate(struct irq_domain *d,
@@ -831,16 +889,8 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
        *out_hwirq = intspec[1] + 16;
 
        /* For SPIs, we need to add 16 more to get the GIC irq ID number */
-       if (!intspec[0]) {
-               ret = gic_routable_irq_domain_ops->xlate(d, controller,
-                                                        intspec,
-                                                        intsize,
-                                                        out_hwirq,
-                                                        out_type);
-
-               if (IS_ERR_VALUE(ret))
-                       return ret;
-       }
+       if (!intspec[0])
+               *out_hwirq += 16;
 
        *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
 
@@ -897,37 +947,11 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
        .xlate = gic_irq_domain_xlate,
 };
 
-/* Default functions for routable irq domain */
-static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq,
-                             irq_hw_number_t hw)
+void gic_set_irqchip_flags(unsigned long flags)
 {
-       return 0;
+       gic_chip.flags |= flags;
 }
 
-static void gic_routable_irq_domain_unmap(struct irq_domain *d,
-                                         unsigned int irq)
-{
-}
-
-static int gic_routable_irq_domain_xlate(struct irq_domain *d,
-                               struct device_node *controller,
-                               const u32 *intspec, unsigned int intsize,
-                               unsigned long *out_hwirq,
-                               unsigned int *out_type)
-{
-       *out_hwirq += 16;
-       return 0;
-}
-
-static const struct irq_domain_ops gic_default_routable_irq_domain_ops = {
-       .map = gic_routable_irq_domain_map,
-       .unmap = gic_routable_irq_domain_unmap,
-       .xlate = gic_routable_irq_domain_xlate,
-};
-
-const struct irq_domain_ops *gic_routable_irq_domain_ops =
-                                       &gic_default_routable_irq_domain_ops;
-
 void __init gic_init_bases(unsigned int gic_nr, int irq_start,
                           void __iomem *dist_base, void __iomem *cpu_base,
                           u32 percpu_offset, struct device_node *node)
@@ -935,7 +959,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
        irq_hw_number_t hwirq_base;
        struct gic_chip_data *gic;
        int gic_irqs, irq_base, i;
-       int nr_routable_irqs;
 
        BUG_ON(gic_nr >= MAX_GIC_NR);
 
@@ -991,15 +1014,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
        gic->gic_irqs = gic_irqs;
 
        if (node) {             /* DT case */
-               const struct irq_domain_ops *ops = &gic_irq_domain_hierarchy_ops;
-
-               if (!of_property_read_u32(node, "arm,routable-irqs",
-                                         &nr_routable_irqs)) {
-                       ops = &gic_irq_domain_ops;
-                       gic_irqs = nr_routable_irqs;
-               }
-
-               gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic);
+               gic->domain = irq_domain_add_linear(node, gic_irqs,
+                                                   &gic_irq_domain_hierarchy_ops,
+                                                   gic);
        } else {                /* Non-DT case */
                /*
                 * For primary GICs, skip over SGIs.