]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/irqchip/irq-crossbar.c
Merge tag 'dt-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[karo-tx-linux.git] / drivers / irqchip / irq-crossbar.c
index c9f068ca7bc9a880d95177fa761c16acb6bad2bd..85c2985d8bcb5040aeae9c343cacc1352fafe125 100644 (file)
@@ -84,10 +84,25 @@ static inline int allocate_free_irq(int cb_no)
        return -ENODEV;
 }
 
+static inline bool needs_crossbar_write(irq_hw_number_t hw)
+{
+       int cb_no;
+
+       if (hw > GIC_IRQ_START) {
+               cb_no = cb->irq_map[hw - GIC_IRQ_START];
+               if (cb_no != IRQ_RESERVED && cb_no != IRQ_SKIP)
+                       return true;
+       }
+
+       return false;
+}
+
 static int crossbar_domain_map(struct irq_domain *d, unsigned int irq,
                               irq_hw_number_t hw)
 {
-       cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]);
+       if (needs_crossbar_write(hw))
+               cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]);
+
        return 0;
 }
 
@@ -106,7 +121,7 @@ static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq)
 {
        irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq;
 
-       if (hw > GIC_IRQ_START) {
+       if (needs_crossbar_write(hw)) {
                cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE;
                cb->write(hw - GIC_IRQ_START, cb->safe_map);
        }
@@ -120,8 +135,19 @@ static int crossbar_domain_xlate(struct irq_domain *d,
 {
        int ret;
        int req_num = intspec[1];
+       int direct_map_num;
 
        if (req_num >= cb->max_crossbar_sources) {
+               direct_map_num = req_num - cb->max_crossbar_sources;
+               if (direct_map_num < cb->int_max) {
+                       ret = cb->irq_map[direct_map_num];
+                       if (ret == IRQ_RESERVED || ret == IRQ_SKIP) {
+                               /* We use the interrupt num as h/w irq num */
+                               ret = direct_map_num;
+                               goto found;
+                       }
+               }
+
                pr_err("%s: requested crossbar number %d > max %d\n",
                       __func__, req_num, cb->max_crossbar_sources);
                return -EINVAL;