root/drivers/irqchip/irq-gic-common.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gic_get_kvm_info
  2. gic_set_kvm_info
  3. gic_enable_of_quirks
  4. gic_enable_quirks
  5. gic_configure_irq
  6. gic_dist_config
  7. gic_cpu_config

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2002 ARM Limited, All Rights Reserved.
   4  */
   5 
   6 #include <linux/interrupt.h>
   7 #include <linux/io.h>
   8 #include <linux/irq.h>
   9 #include <linux/irqchip/arm-gic.h>
  10 
  11 #include "irq-gic-common.h"
  12 
  13 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
  14 
  15 static const struct gic_kvm_info *gic_kvm_info;
  16 
  17 const struct gic_kvm_info *gic_get_kvm_info(void)
  18 {
  19         return gic_kvm_info;
  20 }
  21 
  22 void gic_set_kvm_info(const struct gic_kvm_info *info)
  23 {
  24         BUG_ON(gic_kvm_info != NULL);
  25         gic_kvm_info = info;
  26 }
  27 
  28 void gic_enable_of_quirks(const struct device_node *np,
  29                           const struct gic_quirk *quirks, void *data)
  30 {
  31         for (; quirks->desc; quirks++) {
  32                 if (!of_device_is_compatible(np, quirks->compatible))
  33                         continue;
  34                 if (quirks->init(data))
  35                         pr_info("GIC: enabling workaround for %s\n",
  36                                 quirks->desc);
  37         }
  38 }
  39 
  40 void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
  41                 void *data)
  42 {
  43         for (; quirks->desc; quirks++) {
  44                 if (quirks->compatible)
  45                         continue;
  46                 if (quirks->iidr != (quirks->mask & iidr))
  47                         continue;
  48                 if (quirks->init(data))
  49                         pr_info("GIC: enabling workaround for %s\n",
  50                                 quirks->desc);
  51         }
  52 }
  53 
  54 int gic_configure_irq(unsigned int irq, unsigned int type,
  55                        void __iomem *base, void (*sync_access)(void))
  56 {
  57         u32 confmask = 0x2 << ((irq % 16) * 2);
  58         u32 confoff = (irq / 16) * 4;
  59         u32 val, oldval;
  60         int ret = 0;
  61         unsigned long flags;
  62 
  63         /*
  64          * Read current configuration register, and insert the config
  65          * for "irq", depending on "type".
  66          */
  67         raw_spin_lock_irqsave(&irq_controller_lock, flags);
  68         val = oldval = readl_relaxed(base + confoff);
  69         if (type & IRQ_TYPE_LEVEL_MASK)
  70                 val &= ~confmask;
  71         else if (type & IRQ_TYPE_EDGE_BOTH)
  72                 val |= confmask;
  73 
  74         /* If the current configuration is the same, then we are done */
  75         if (val == oldval) {
  76                 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
  77                 return 0;
  78         }
  79 
  80         /*
  81          * Write back the new configuration, and possibly re-enable
  82          * the interrupt. If we fail to write a new configuration for
  83          * an SPI then WARN and return an error. If we fail to write the
  84          * configuration for a PPI this is most likely because the GIC
  85          * does not allow us to set the configuration or we are in a
  86          * non-secure mode, and hence it may not be catastrophic.
  87          */
  88         writel_relaxed(val, base + confoff);
  89         if (readl_relaxed(base + confoff) != val)
  90                 ret = -EINVAL;
  91 
  92         raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
  93 
  94         if (sync_access)
  95                 sync_access();
  96 
  97         return ret;
  98 }
  99 
 100 void gic_dist_config(void __iomem *base, int gic_irqs,
 101                      void (*sync_access)(void))
 102 {
 103         unsigned int i;
 104 
 105         /*
 106          * Set all global interrupts to be level triggered, active low.
 107          */
 108         for (i = 32; i < gic_irqs; i += 16)
 109                 writel_relaxed(GICD_INT_ACTLOW_LVLTRIG,
 110                                         base + GIC_DIST_CONFIG + i / 4);
 111 
 112         /*
 113          * Set priority on all global interrupts.
 114          */
 115         for (i = 32; i < gic_irqs; i += 4)
 116                 writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
 117 
 118         /*
 119          * Deactivate and disable all SPIs. Leave the PPI and SGIs
 120          * alone as they are in the redistributor registers on GICv3.
 121          */
 122         for (i = 32; i < gic_irqs; i += 32) {
 123                 writel_relaxed(GICD_INT_EN_CLR_X32,
 124                                base + GIC_DIST_ACTIVE_CLEAR + i / 8);
 125                 writel_relaxed(GICD_INT_EN_CLR_X32,
 126                                base + GIC_DIST_ENABLE_CLEAR + i / 8);
 127         }
 128 
 129         if (sync_access)
 130                 sync_access();
 131 }
 132 
 133 void gic_cpu_config(void __iomem *base, int nr, void (*sync_access)(void))
 134 {
 135         int i;
 136 
 137         /*
 138          * Deal with the banked PPI and SGI interrupts - disable all
 139          * private interrupts. Make sure everything is deactivated.
 140          */
 141         for (i = 0; i < nr; i += 32) {
 142                 writel_relaxed(GICD_INT_EN_CLR_X32,
 143                                base + GIC_DIST_ACTIVE_CLEAR + i / 8);
 144                 writel_relaxed(GICD_INT_EN_CLR_X32,
 145                                base + GIC_DIST_ENABLE_CLEAR + i / 8);
 146         }
 147 
 148         /*
 149          * Set priority on PPI and SGI interrupts
 150          */
 151         for (i = 0; i < nr; i += 4)
 152                 writel_relaxed(GICD_INT_DEF_PRI_X4,
 153                                         base + GIC_DIST_PRI + i * 4 / 4);
 154 
 155         /* Ensure all SGI interrupts are now enabled */
 156         writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
 157 
 158         if (sync_access)
 159                 sync_access();
 160 }

/* [<][>][^][v][top][bottom][index][help] */