cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

irq-gic-common.c (3698B)


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