@@ -73,6 +73,7 @@ struct gic_chip_data {
struct irq_domain *domain;
unsigned int gic_irqs;
u32 igroup0_shadow;
+ bool sgi_with_nsatt;
#ifdef CONFIG_GIC_NON_BANKED
void __iomem *(*get_base)(union gic_base *);
#endif
@@ -512,16 +513,27 @@ static void __init gic_dist_init(struct gic_chip_data
writel_relaxed(GICD_ENABLE_GRP1 | GICD_ENABLE, base + GIC_DIST_CTRL);
/*
- * Set all global interrupts to be group 1 if (and only if) it
- * is possible to enable group 1 interrupts. This register is RAZ/WI
- * if not accessible or not implemented, however some GICv1 devices
- * do not implement the EnableGrp1 bit making it unsafe to set
- * this register unconditionally.
+ * Some GICv1 devices (even those with security extensions) do not
+ * implement EnableGrp1 meaning some parts of the above write might
+ * be ignored. We will only enable FIQ support if the bit can be set.
*/
- if (GICD_ENABLE_GRP1 & readl_relaxed(base + GIC_DIST_CTRL))
+ if (GICD_ENABLE_GRP1 & readl_relaxed(base + GIC_DIST_CTRL)) {
+ /*
+ * Set all global interrupts to be group 1 (signalled with
+ * IRQ).
+ */
for (i = 32; i < gic_irqs; i += 32)
writel_relaxed(0xffffffff,
base + GIC_DIST_IGROUP + i * 4 / 32);
+
+ /*
+ * If the GIC supports the security extension then SGIs
+ * will be filtered based on the value of NSATT. If the
+ * GIC has this support then enable NSATT support.
+ */
+ if (GICD_SECURITY_EXTN & readl_relaxed(base + GIC_DIST_CTR))
+ gic->sgi_with_nsatt = true;
+ }
}
static void gic_cpu_init(struct gic_chip_data *gic)
@@ -782,6 +794,7 @@ static void gic_raise_softirq(const struct cpumask *mask,
int cpu;
unsigned long map = 0;
unsigned long softint;
+ void __iomem *dist_base;
gic_migration_lock();
@@ -789,20 +802,20 @@ static void gic_raise_softirq(const struct cpumask *mask,
for_each_cpu(cpu, mask)
map |= gic_cpu_map[cpu];
+ /* This always happens on GIC0 */
+ dist_base = gic_data_dist_base(&gic_data[0]);
+
/*
* Ensure that stores to Normal memory are visible to the
* other CPUs before they observe us issuing the IPI.
*/
dmb(ishst);
- /* We avoid a readl here by using the shadow copy of IGROUP[0] */
softint = map << 16 | irq;
- if (gic_data[0].igroup0_shadow & BIT(irq))
- softint |= 0x8000;
- /* This always happens on GIC0 */
- writel_relaxed(softint,
- gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+ writel_relaxed(softint, dist_base + GIC_DIST_SOFTINT);
+ if (gic_data[0].sgi_with_nsatt)
+ writel_relaxed(softint | 0x8000, dist_base + GIC_DIST_SOFTINT);
gic_migration_unlock();
}
@@ -50,6 +50,7 @@
#define GICD_ENABLE 0x1
#define GICD_ENABLE_GRP1 0x2
#define GICD_DISABLE 0x0
+#define GICD_SECURITY_EXTN 0x400
#define GICD_INT_ACTLOW_LVLTRIG 0x0
#define GICD_INT_EN_CLR_X32 0xffffffff
#define GICD_INT_EN_SET_SGI 0x0000ffff